Why the Same SQL Query Looks Different in MySQL, Postgres, and BigQuery
SQL is a standard in name only — every database vendor extends and bends it differently, which is why a query that runs perfectly in one often needs edits to run in another.
SQL has been an ANSI/ISO standard since 1986, and yet copying a query from a MySQL project into a Postgres one routinely breaks. The standard exists, but every major database implements a superset of it, with its own extensions and its own quirks — and those differences are exactly where queries stop being portable.
Quoting identifiers: three different characters
Referring to a column or table name that needs escaping (because it clashes with a reserved word, or contains a space) uses different syntax depending on the database:
- Standard SQL / PostgreSQL: double quotes —
"order" - MySQL / MariaDB: backticks —
`order` - SQL Server (T-SQL): square brackets —
[order]
A query quoted for one of these fails to parse correctly (or parses as something else entirely) in another, since the "wrong" quote character is either a syntax error or, worse, silently interpreted as a plain string literal instead of an identifier.
Limiting results: no shared syntax at all
Every database needs a way to cap how many rows come back, and there's essentially no agreement on the keyword:
- MySQL / PostgreSQL / SQLite:
LIMIT 10 - SQL Server:
TOP 10(placed right afterSELECT, not at the end of the query) - Oracle (older versions): no
LIMITat all — historically done with aROWNUMfilter in theWHEREclause instead, a much less obvious pattern to someone coming from aLIMIT-based database.
This is one of the most common "porting a query between databases" surprises, precisely because it's such a basic, constantly-used operation with zero standardization.
String concatenation: another three-way split
- Standard SQL / PostgreSQL / Oracle:
'a' || 'b' - MySQL:
CONCAT('a', 'b')(the||operator means something else there by default — logical OR, unless a special mode is enabled) - SQL Server:
'a' + 'b'
Using || on MySQL without the right mode enabled doesn't error — it silently evaluates as a boolean OR expression instead, which is the kind of bug that produces a confusing wrong result rather than a clear failure, and can go unnoticed for a while.
Date/time functions: barely any overlap
Getting "now" alone has almost no shared syntax: NOW() (MySQL), CURRENT_TIMESTAMP (standard, widely supported), GETDATE() (SQL Server), SYSDATE (Oracle). Date arithmetic (adding days to a date, extracting a part of a date) diverges even further, which is why date-heavy queries are often the least portable part of any SQL codebase.
Why cloud warehouses add yet another layer
Modern analytical databases — BigQuery, Snowflake, Spark SQL — build on standard SQL but add their own dialect-specific functions and syntax for their distributed-computing models (array/struct types, specific window function extensions, dataset/schema-qualified naming conventions). A query written for a traditional row-oriented database frequently needs real rewriting, not just reformatting, to run efficiently — or at all — on one of these.
Why a dialect-aware formatter actually matters
Because bracket style, keyword casing conventions, and even valid syntax differ by dialect, a formatter that doesn't know which dialect it's formatting can produce output that looks fine but subtly changes meaning (or simply won't parse) once run against the real target database — reformatting [order] as if it were a generic string, for instance, rather than recognizing it as a SQL Server identifier.
Spellkit's SQL Formatter understands eleven dialects — MySQL, PostgreSQL, SQLite, MariaDB, SQL Server (T-SQL), Oracle PL/SQL, BigQuery, Snowflake, Spark, Hive, and standard SQL — so dialect-specific syntax formats correctly instead of getting mangled by a one-size-fits-all formatter, entirely in your browser.
