Ana içeriğe geç
Kesit SQL
İleri · Modern SQL

SQL ile JSON verisi

Yarı yapılandırılmış veriyi sorgulamak ve üretmek; SQL türleri arası farklar.

Uygulamada aç, 5 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Neden JSON?

Uygulama olayları, API yanıtları ve esnek nitelikler çoğu zaman JSON olarak gelir. SQL:2016 ile JSON desteği standarda girdi; ama her SQL türü kendi fonksiyonlarını kullanır.

İşlemSQL ServerPostgreSQLMySQLOracleSQLite
Alan okuJSON_VALUE(j, '$.a.b')j->'a'->>'b'j->>'$.a.b'JSON_VALUE(j, '$.a.b')json_extract(j, '$.a.b')
Diziyi satırlara açOPENJSONjsonb_array_elementsJSON_TABLEJSON_TABLEjson_each
JSON üretFOR JSON PATH, JSON_OBJECT (2022)json_build_object, json_aggJSON_OBJECT, JSON_ARRAYAGGJSON_OBJECT, JSON_ARRAYAGGjson_object, json_group_array
WITH olaylar(id, payload) AS (
  VALUES (1, '{"user": {"id": 7, "city": "Bursa"}, "total": 420}'),
         (2, '{"user": {"id": 9, "city": "Konya"}, "total": 2499}')
)
SELECT id,
       json_extract(payload, '$.user.city') AS sehir,
       json_extract(payload, '$.total') AS toplam
FROM olaylar;

SQL ile JSON üretmek

SELECT json_object('id', customer_id, 'ad', first_name, 'sehir', city) AS musteri_json
FROM customers
ORDER BY customer_id
LIMIT 3;

Derinleş: JSON ile çalışırken SQL türleri arası farklar

JSON fonksiyonlarının adları SQL türüne göre değişir, ama asıl farklar daha derindedir: saklama tipi, dönen değerin tipi ve dizileri satırlara açma yöntemi.

SQL türüSaklamaNot
PostgreSQLjson (metin olarak) ve jsonb (ikili, indekslenebilir)Analitik için jsonb + GIN indeks
MySQLJSON tipi (doğrulanır, ikili saklanır)Üretilmiş (generated) sütunla indekslenir
SQL ServerAyrı tip yok (2025 öncesi): NVARCHAR(MAX)ISJSON() ile CHECK kısıtı ekle
OracleJSON (21c+), öncesinde CLOB + IS JSONNokta yazımı: t.j.user.city
BigQueryJSON tipi ya da STRINGJSON_VALUE, JSON_QUERY_ARRAY
SQLiteMetinjson_extract sayıyı sayı olarak döndürür

Dönen tip tuzağı

PostgreSQL'de ->>, SQL Server ve Oracle'da JSON_VALUE her zaman metin döndürür. '9' > '10' metin karşılaştırmasında doğrudur; sıralama ve filtrede sayısal alanı mutlaka CAST et:

WITH t AS (
  SELECT restaurant_id,
         json_object('ad', name, 'sehir', city, 'komisyon', commission_pct) AS j
  FROM lk_restaurants
)
SELECT json_extract(j, '$.sehir') AS sehir, COUNT(*) AS restoran
FROM t
WHERE CAST(json_extract(j, '$.komisyon') AS REAL) >= 20
GROUP BY json_extract(j, '$.sehir')
ORDER BY sehir;

Diziyi satırlara açmak

Olay verisinde etiketler çoğu zaman bir dizi olarak gelir. Etiket başına sayım için dizi satırlara açılır: SQLite'ta json_each, SQL Server'da CROSS APPLY OPENJSON.

WITH olaylar(id, payload) AS (
  VALUES (1, '{"user": 7, "etiketler": ["indirim", "mobil"]}'),
         (2, '{"user": 9, "etiketler": ["mobil"]}'),
         (3, '{"user": 7, "etiketler": []}')
)
SELECT j.value AS etiket, COUNT(*) AS olay
FROM olaylar o, json_each(json_extract(o.payload, '$.etiketler')) j
GROUP BY j.value
ORDER BY olay DESC, etiket;
-- PostgreSQL
SELECT e.etiket, COUNT(*) FROM olaylar o
CROSS JOIN LATERAL jsonb_array_elements_text(o.payload -> 'etiketler') AS e(etiket)
GROUP BY e.etiket;

-- MySQL 8 / Oracle
SELECT jt.etiket, COUNT(*) FROM olaylar o,
JSON_TABLE(o.payload, '$.etiketler[*]' COLUMNS (etiket VARCHAR(50) PATH '$')) jt
GROUP BY jt.etiket;

Boş dizili 3 numaralı olay sonuçta görünmez; çünkü açılacak eleman yoktur (iç birleştirme gibi davranır). “Etiketsiz olay” sayısı da gerekiyorsa ayrıca hesapla ya da LEFT JOIN LATERAL / OUTER APPLY kullan.

Performans: JSON içindeki bir alana göre sık filtreleme yapılıyorsa her satırda metni yeniden ayrıştırmak pahalıdır. PostgreSQL'de jsonb sütununa GIN indeks, MySQL'de alanı üretilmiş sütuna çıkarıp indeksleme (ALTER TABLE t ADD sehir VARCHAR(50) AS (j->>'$.sehir'), ADD INDEX (sehir)), SQL Server'da hesaplanmış sütun + indeks kullanılır.

Ne zaman JSON, ne zaman sütun?Sık filtrelenen, raporlanan veya birleştirilen alanları gerçek sütunlara çıkar. JSON'u gerçekten esnek, seyrek ve kaynağa göre değişen nitelikler için bırak.
Alıştırmalara geç (5)