SQL dialect differences: what changes between databases

SELECT, WHERE, GROUP BY, JOIN and CASE work the same in every major database. The differences are in the details around them. The examples run in PostgreSQL, which this site uses; each section lists how the others do it.

Limiting the number of rows

PostgreSQL, MySQL and SQLite use LIMIT (with OFFSET to skip rows). SQL Server uses SELECT TOP n, or OFFSET ... FETCH after ORDER BY. Oracle 12c and newer, and also PostgreSQL, accept the standard FETCH FIRST n ROWS ONLY.

SELECT name, unit_price
FROM products
ORDER BY unit_price DESC
FETCH FIRST 3 ROWS ONLY;

Result: The three most expensive products, using the standard syntax that PostgreSQL and Oracle share.

Joining text

PostgreSQL, SQLite and Oracle join text with ||. SQL Server uses + (or CONCAT). In MySQL, || means OR unless a setting is changed, so use CONCAT(). CONCAT works in PostgreSQL, MySQL and SQL Server and is the most portable.

SELECT CONCAT(first_name, ' ', last_name) AS full_name
FROM customers
ORDER BY customer_id;

Result: Each customer's full name.

Today's date

PostgreSQL has CURRENT_DATE and NOW(). MySQL has CURDATE() and NOW(). SQL Server has GETDATE(). SQLite uses date('now'). Oracle uses SYSDATE. CURRENT_DATE is standard SQL and works in PostgreSQL, MySQL and Oracle.

SELECT CURRENT_DATE AS today;

Result: One row with today's date.

Integer division

In PostgreSQL, SQL Server and SQLite, 7 / 2 is 3 when both numbers are integers. In MySQL and Oracle it is 3.5. To get the same result everywhere, cast one side to a decimal type first.

SELECT 7 / 2 AS integer_division, 7 / 2.0 AS with_decimal;

Result: 3 and 3.5 in PostgreSQL.

Joining the values of a group

STRING_AGG exists in PostgreSQL and in SQL Server 2017 and newer. MySQL and SQLite call it GROUP_CONCAT. Oracle calls it LISTAGG.

SELECT city, STRING_AGG(first_name, ', ' ORDER BY first_name) AS names
FROM customers
GROUP BY city
ORDER BY city;

Result: The customers of each city in one text.

Case, quotes and auto-numbering

Text comparison: PostgreSQL's LIKE is case-sensitive (use ILIKE for the opposite); MySQL and SQL Server usually compare text without case by default, depending on the collation; SQLite's LIKE ignores case for plain English letters.

Quoting a name: standard SQL uses double quotes, as PostgreSQL, Oracle and SQLite do. MySQL uses backticks and SQL Server square brackets.

Auto-numbering a key: PostgreSQL uses GENERATED ... AS IDENTITY (or serial), MySQL AUTO_INCREMENT, SQL Server IDENTITY(1,1), SQLite INTEGER PRIMARY KEY, and Oracle 12c and newer GENERATED AS IDENTITY.

SELECT name FROM products WHERE name ILIKE 'CROISSANT';

Result: The Croissant, found despite the capital letters, because ILIKE ignores case.

Common questions

Which database should I learn first?
Any of them. The core transfers almost completely. PostgreSQL follows the standard closely, which makes it a good first choice.
Will my queries from this site run in MySQL or SQL Server?
Most basic ones will. The parts to change are the ones in this guide: LIMIT, ILIKE, ||, date functions, STRING_AGG and the RETURNING clause.

Practise it