ToolSite
All posts

MySQL vs PostgreSQL vs SQL Server: Formatting Differences

SQL formatting across MySQL, PostgreSQL, and SQL Server. Quoting, LIMIT vs TOP, concatenation, auto-increment, boolean types, and case sensitivity examples.

By ToolSite6 min readguides

Same Language, Different Dialects

SQL is a standard, but no database implements it identically. The formatting differences are small but persistent. When you switch between MySQL, PostgreSQL, and SQL Server, the same query often needs syntax adjustments. A formatter that knows the dialect applies the right rules automatically.

Identifier Quoting

DatabaseQuote CharacterExample
MySQLBacktick`user_id`
PostgreSQLDouble quote"user_id"
SQL ServerSquare brackets (default)[user_id]

All three support the SQL standard double-quote, but default conventions differ. A formatter set to the correct dialect applies the right quoting style to reserved word collisions.

When you name a column order or a table group, the formatter adds the dialect-appropriate quotes. In MySQL: `order`. In PostgreSQL: "order". In SQL Server: [order]. Without quotes, those identifiers parse as keywords and the query fails.

String Literals and Concatenation

DatabaseEscapeConcatenation
MySQL'it''s' or "it's" (non-ANSI mode)CONCAT(a, b)
PostgreSQL'it''s' or $$it's$$ (dollar quoting)`a
SQL Server'it''s'a + b or CONCAT(a, b)

String concatenation is the most visible difference. 'Hello ' || name works in PostgreSQL. 'Hello ' + name works in SQL Server. MySQL uses CONCAT().

PostgreSQL's dollar quoting ($$...$$) lets you embed single quotes without escaping. This is especially useful in function bodies and dynamic SQL:

-- PostgreSQL dollar quoting
SELECT $$It's a "quoted" string$$;
-- No escaping needed for single or double quotes

-- Equivalent with standard escaping
SELECT 'It''s a "quoted" string';

Limiting Results

-- MySQL / PostgreSQL
SELECT * FROM users LIMIT 10;

-- SQL Server
SELECT TOP 10 * FROM users;
-- or (SQL Server 2012+)
SELECT * FROM users OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;

LIMIT is the de facto standard (MySQL, PostgreSQL, SQLite). SQL Server uses TOP or the OFFSET...FETCH syntax, which is the SQL:2008 standard. A formatter keeps these dialect-specific keywords as-is.

When you format a query with LIMIT and switch the dialect to SQL Server, the formatter does not auto-convert LIMIT to TOP. It preserves the intent. You must rewrite the query manually for cross-database portability.

Pagination Differences

-- MySQL / PostgreSQL: LIMIT with OFFSET
SELECT * FROM users ORDER BY id LIMIT 20 OFFSET 40;

-- SQL Server: OFFSET...FETCH
SELECT * FROM users ORDER BY id OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY;

-- MySQL also supports shorthand
SELECT * FROM users ORDER BY id LIMIT 40, 20;
-- LIMIT offset, count

The MySQL shorthand LIMIT offset, count reverses the argument order from the standard OFFSET...LIMIT. If you format a MySQL query with the shorthand, the formatter preserves it as-is.

Auto-Increment Columns

-- MySQL
id INT AUTO_INCREMENT PRIMARY KEY

-- PostgreSQL
id SERIAL PRIMARY KEY
-- or (PG 10+)
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY

-- SQL Server
id INT IDENTITY(1,1) PRIMARY KEY

SERIAL in PostgreSQL is syntactic sugar for creating a sequence and setting the default. GENERATED ALWAYS AS IDENTITY is the SQL-standard approach and preferred for new projects. IDENTITY(1,1) in SQL Server means start at 1, increment by 1.

Boolean Types

DatabaseBoolean Type
MySQLBOOLEAN (alias for TINYINT(1))
PostgreSQLBOOLEAN (native type)
SQL ServerBIT

PostgreSQL has a true boolean type with TRUE, FALSE, and NULL. You can write WHERE active instead of WHERE active = TRUE. MySQL's BOOLEAN is a TINYINT and accepts 0 and 1 (and other integers). SQL Server uses BIT (0, 1, or NULL).

These differences affect how you write conditions:

-- PostgreSQL: native boolean
SELECT * FROM users WHERE active;
SELECT * FROM users WHERE NOT active;

-- MySQL: works but treats 0 as false, non-zero as true
SELECT * FROM users WHERE active;
SELECT * FROM users WHERE NOT active;

-- SQL Server: BIT requires explicit comparison
SELECT * FROM users WHERE active = 1;
SELECT * FROM users WHERE active = 0;

Case Sensitivity

DatabaseDefault Case Sensitivity
MySQLCase-insensitive (depends on collation)
PostgreSQLCase-sensitive (lowercase unless quoted)
SQL ServerCase-insensitive (depends on collation)

In PostgreSQL, SELECT * FROM Users fails if the table was created as users (unquoted identifiers are folded to lowercase). In MySQL and SQL Server, case of unquoted identifiers doesn't matter by default. This affects how you format table and column references.

If you create a table in PostgreSQL with CREATE TABLE "Users", you must reference it as "Users" (with quotes, exact case) forever. Avoid quoted identifiers in PostgreSQL unless you have a specific reason. Use snake_case for all names.

Function Names

SQL functions (COUNT, SUM, AVG, COALESCE) are case-insensitive in all three databases. The SQL Formatter uppercases them for readability, and this is safe across dialects.

Vendor-specific functions differ:

MySQLPostgreSQLSQL Server
NOW()NOW()GETDATE()
IFNULL(a, b)COALESCE(a, b)ISNULL(a, b)
GROUP_CONCAT()STRING_AGG()STRING_AGG()
REGEXP~LIKE with patterns
IF(cond, a, b)CASE WHEN cond THEN a ELSE b ENDIIF(cond, a, b)
DATE_FORMAT()TO_CHAR()FORMAT()

When formatting, these vendor-specific functions are preserved as-is. The formatter does not convert GETDATE() to NOW(). That's a migration concern, not a formatting concern.

Data Type Differences

-- MySQL
TEXT, MEDIUMTEXT, LONGTEXT

-- PostgreSQL
TEXT (unlimited) or VARCHAR(n)

-- SQL Server
VARCHAR(MAX) or NVARCHAR(MAX)

PostgreSQL's TEXT type is unlimited. MySQL has multiple text types with different size limits. SQL Server uses VARCHAR(MAX) for large text.

Comment Styles

All three databases support -- for single-line comments and /* */ for block comments. MySQL also supports # for single-line comments (non-standard). A formatter should preserve comment style while ensuring the query remains valid.

-- Standard single-line comment (all databases)
SELECT * FROM users;

/* Block comment
   spanning multiple lines (all databases) */
SELECT * FROM orders;

# MySQL-only single-line comment (not portable)
SELECT * FROM products;

Using the Formatter

The SQL Formatter lets you select a dialect before formatting. It preserves dialect-specific keywords (TOP, LIMIT, SERIAL) and adjusts quoting conventions.

Try it yourself: open the SQL Formatter. Switch the dialect between MySQL, PostgreSQL, and SQL Standard. Paste SELECT `user_id`, `name` FROM `users` (MySQL-style backtick quoting) and format it. Change to PostgreSQL dialect and observe how the formatter handles the backtick quoting in the output. Try a query with LIMIT and switch to SQL Server to see how it is preserved.

Related Reading