Chapter 17 · SQL Dialects, Tools, and Application Access
ANSI SQL and Major Vendor Dialects
SQL is a standardized language family implemented by products with different types, functions, syntax, limits, and operational behavior. Professional portability begins by separating relational intent from dialect-specific mechanisms and testing the exact engines you support.
Learning outcomes
Learning outcomes
Explain the relationship between ISO/IEC SQL standards and product dialects.
Identify portability risks in identifiers, types, functions, pagination, generated values, UPSERT, JSON, and DDL.
Write a conservative SQL baseline and isolate vendor-specific capabilities behind explicit boundaries.
Build capability probes that fail early on unsupported engines or versions.
Decide when portability is valuable and when a deliberate vendor commitment is justified.
One language family, many implementations
Standard SQL
The standards define grammar, semantics, data types, modules, and optional features. They are specifications—not one executable product.
Dialect
A database engine implements a subset, adds extensions, and may assign different behavior to similar syntax.
Driver layer
Parameter markers, type conversion, generated-key retrieval, and transaction APIs can differ even when SQL text is identical.
Operational semantics
DDL transactions, locking, isolation defaults, identifier folding, and error behavior affect deployments beyond syntax.
Portability is an architecture and verification problem, not a search-and-replace exercise.
Portability dimensions
| Dimension | Portable starting point | Common divergence |
|---|---|---|
| Identifiers | lowercase unquoted names; avoid reserved words | Case folding, maximum length, quoting with double quotes/backticks/brackets |
| Generated keys | standard identity concepts where available | INTEGER PRIMARY KEY, SERIAL/IDENTITY, AUTO_INCREMENT, sequences |
| Boolean values | BOOLEAN intent | Native Boolean, integer 0/1, BIT, truthy expressions |
| Date/time | typed timestamps and explicit time-zone policy | Function names, interval syntax, storage precision, offset handling |
| Pagination | ORDER BY plus standard OFFSET/FETCH where supported | LIMIT/OFFSET, TOP, FETCH FIRST; optimizer and tie behavior |
| Upsert | separate existence decision or adapter | ON CONFLICT, ON DUPLICATE KEY UPDATE, MERGE |
| Returned rows | follow-up SELECT in portable code | RETURNING, OUTPUT, driver generated-key APIs |
| JSON | store only when shape is genuinely semi-structured | JSON/JSONB types, path syntax, indexes, functions |
| DDL | small additive changes | Implicit commits, ALTER TABLE breadth, online options, transactional DDL |
A conservative relational baseline
CREATE TABLE customer ( customer_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, email VARCHAR(320) NOT NULL UNIQUE, display_name VARCHAR(200) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);SELECT customer_id, email, display_nameFROM customerWHERE created_at >= ?ORDER BY created_at, customer_idFETCH FIRST 100 ROWS ONLY;The schema expresses intent with standard concepts, but the parameter marker and generated-identity syntax still need validation for each driver and engine.
Equivalent intent, different syntax
| Task | SQLite | PostgreSQL | MySQL | SQL Server | Oracle |
|---|---|---|---|---|---|
| First 10 rows | LIMIT 10 | LIMIT 10 or FETCH FIRST | LIMIT 10 | TOP (10) or OFFSET/FETCH | FETCH FIRST 10 ROWS ONLY |
| String combine | a || b | a || b or concat | concat(a,b) | a + b or concat | a || b |
| Case-insensitive match | LIKE depends on settings/collation | ILIKE | collation-dependent LIKE | collation-dependent LIKE | collation-dependent comparison |
| Upsert | ON CONFLICT | ON CONFLICT | ON DUPLICATE KEY UPDATE | MERGE | MERGE |
| Return changed rows | RETURNING | RETURNING | driver/follow-up SELECT | OUTPUT | RETURNING INTO |
Capability probes
-- Run in an isolated scratch schema during certification.WITH probe(value) AS (VALUES (1))SELECT value FROM probe;CREATE TEMPORARY TABLE capability_probe ( id INTEGER PRIMARY KEY, payload TEXT NOT NULL);INSERT INTO capability_probe(id,payload)VALUES (1,'first')ON CONFLICT(id) DO UPDATE SET payload=excluded.payloadRETURNING id,payload;DROP TABLE capability_probe;engine: postgresqlminimum_version: 16required: - recursive_cte - window_functions - transactional_ddl - returningoptional: - json_path - generated_columnsunsupported_path: fail_startupProbe behavior in CI against every supported engine version. Documentation review is necessary, but executable certification catches driver settings, compatibility modes, and cloud-service restrictions.
Portability strategies
| Strategy | Best fit | Cost |
|---|---|---|
| Lowest common denominator | Small application supporting several engines equally | Leaves useful engine features unused |
| Dialect adapters | A stable domain with a few known syntax differences | Requires explicit interfaces and multi-engine tests |
| SQL toolkit/compiler | Programmatic query composition across engines | Generated SQL must still be inspected and tested |
| Vendor-first design | Performance-sensitive or feature-rich platform | Migration to another engine becomes a separate project |
| Read/write split by contract | Portable writes, engine-specific analytics | More code paths and operational ownership |
SQLite laboratory
PRAGMA foreign_keys = ON;DROP TABLE IF EXISTS order_item;DROP TABLE IF EXISTS sales_order;DROP TABLE IF EXISTS product;DROP TABLE IF EXISTS customer;CREATE TABLE customer ( customer_id INTEGER PRIMARY KEY, email TEXT NOT NULL UNIQUE, display_name TEXT NOT NULL, region TEXT NOT NULL CHECK(region IN ('north','south','east','west')), created_at TEXT NOT NULL) STRICT;CREATE TABLE product ( product_id INTEGER PRIMARY KEY, sku TEXT NOT NULL UNIQUE, product_name TEXT NOT NULL, unit_price_cents INTEGER NOT NULL CHECK(unit_price_cents>=0), active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0,1))) STRICT;CREATE TABLE sales_order ( order_id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL REFERENCES customer(customer_id), status TEXT NOT NULL CHECK(status IN ('draft','submitted','paid','cancelled')), ordered_at TEXT NOT NULL, request_key TEXT UNIQUE) STRICT;CREATE TABLE order_item ( order_id INTEGER NOT NULL REFERENCES sales_order(order_id) ON DELETE CASCADE, product_id INTEGER NOT NULL REFERENCES product(product_id), quantity INTEGER NOT NULL CHECK(quantity>0), unit_price_cents INTEGER NOT NULL CHECK(unit_price_cents>=0), PRIMARY KEY(order_id,product_id)) STRICT;INSERT INTO customer VALUES(1,'ada@example.com','Ada Lovelace','north','2026-01-10'),(2,'grace@example.com','Grace Hopper','east','2026-02-15'),(3,'linus@example.com','Linus Torvalds','west','2026-03-01');INSERT INTO product VALUES(10,'DB-BOOK','Database Design Handbook',4200,1),(11,'SQL-CARD','SQL Reference Cards',1800,1),(12,'ARCHIVE','Archived Product',9900,0);INSERT INTO sales_order VALUES(1001,1,'paid','2026-08-01 09:00:00','req-1001'),(1002,1,'submitted','2026-08-02 10:30:00','req-1002'),(1003,2,'draft','2026-08-03 14:15:00','req-1003');INSERT INTO order_item VALUES(1001,10,1,4200),(1001,11,2,1800),(1002,11,3,1800),(1003,10,1,4200);SELECT c.region, COUNT(*) AS customersFROM customer AS cGROUP BY c.regionORDER BY c.region;INSERT INTO product(product_id,sku,product_name,unit_price_cents)VALUES(11,'SQL-CARD','SQL Cards, revised',1900)ON CONFLICT(product_id) DO UPDATE SET product_name=excluded.product_name, unit_price_cents=excluded.unit_price_centsRETURNING product_id,sku,unit_price_cents;Portability review
Review the design
- Why does valid SQL on one engine not prove portability?
- Why should identifiers be kept simple and unquoted when possible?
- When is vendor-specific SQL the better engineering choice?
- What belongs in a capability manifest?
Review the answers
The standard contains optional features and products add or reinterpret behavior. Simple names avoid case-folding and quoting traps. Vendor-specific SQL is appropriate when its value exceeds portability needs and the commitment is explicit. A manifest records engine/version constraints, required capabilities, optional capabilities, and the policy for unsupported environments.
Lesson summary
- SQL standards provide a common model, not identical implementations.
- Portability includes syntax, types, driver APIs, transactions, DDL, and operations.
- Keep a conservative core, isolate extensions, and certify every supported engine.
- Choose portability deliberately rather than accidentally limiting or coupling the system.