Skip to content
Spellkit

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 after SELECT, not at the end of the query)
  • Oracle (older versions): no LIMIT at all — historically done with a ROWNUM filter in the WHERE clause instead, a much less obvious pattern to someone coming from a LIMIT-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.