Working with JSON and Semi-Structured Data

1. Storing JSON in SQL Databases

DBType
PostgresJSON (text), JSONB (binary, indexable)
MySQL 8JSON (binary)
SQL ServerNVARCHAR + JSON functions
OracleJSON (21c+), BLOB/CLOB earlier
SQLiteTEXT + JSON1 extension

2. Querying JSON Fields

Example: PG JSONB Queries

-- access
SELECT data->>'name', data#>>'{address,city}' FROM users;
-- contains
SELECT * FROM users WHERE data @> '{"status":"active"}';
-- key exists
SELECT * FROM users WHERE data ? 'phone';
-- jsonb_path_query
SELECT jsonb_path_query(data, '$.orders[*] ? (@.total > 100)') FROM users;

3. Indexing JSON Documents

IndexUse
GIN on JSONBGeneric — supports @>, ?, ?|, ?&
GIN jsonb_path_opsSmaller, only @> — faster
Expression indexbtree on (data->>'email')
MySQL functional indexOn JSON_EXTRACT path

4. Validating JSON Structure

ToolDetail
PG CHECK constraintCHECK (jsonb_typeof(data) = 'object')
pg_jsonschema / is_jsonb_validExtension-based schema validation
MySQL JSON_SCHEMA_VALIDBuilt-in 8.0.17+
App layerAjv / Pydantic / Zod

5. Modeling Hybrid Relational-JSON

PatternDetail
Stable columns + JSON extrasStrict for queryable; flexible for the rest
Per-tenant custom fieldsJSONB column with per-tenant schema
Avoid JSON for joinsPromote frequently-joined keys to columns
Versioningschema_version inside JSON

6. Handling XML Data

DBSupport
PostgresXML type, XPath, xmltable()
SQL ServerXML type, XQuery, typed XML
OracleXMLType, XQuery
Modern preferenceJSON over XML for new systems

7. Implementing JSON Path Expressions

ExpressionMeaning
$Root
$.a.bField navigation
$.items[*]All array elements
$.items[0]First element
$.items[*] ? (@.qty > 5)Filter
$.* / $..bWildcard / recursive descent

8. Converting Between JSON and Tables

Example: jsonb_to_recordset / json_table

-- Postgres
SELECT * FROM jsonb_to_recordset('[{"id":1,"name":"a"},{"id":2,"name":"b"}]')
AS x(id INT, name TEXT);

-- MySQL 8 / Oracle
SELECT * FROM JSON_TABLE('[{"id":1},{"id":2}]', '$[*]'
  COLUMNS (id INT PATH '$.id')) AS jt;

9. Designing Flexible Schemas

TipDetail
Use JSON for variabilityOptional / sparse fields
Promote hot fieldsTo real columns when stable
Document expected keysEven when not enforced
Lint at write timeCatch typos early

10. Optimizing JSON Query Performance

TipDetail
Prefer JSONB over JSONParsed once, indexable
GIN + jsonb_path_opsSmaller, faster for @>
Expression index for hot keysbtree(data->>'email')
Promote hot fieldsReal columns + indexes
Avoid deep paths in WHEREIndex can't cover