PostgreSQL'de iç içe JSON belgelerinden veri çekmenin standart yolu SQL/JSON'dur: $.kalemler[*] ? (@.adet >= 5).urun gibi bir jsonpath ifadesi belgede gezinip filtre uygular, JSON_VALUE tek bir skaler değeri SQL tipine çevirir, JSON_QUERY nesne ya da dizi döndürür, JSON_EXISTS bir yolun eşleşip eşleşmediğini söyler, JSON_TABLE ise JSON dizisini doğrudan satır ve sütunlara açar. Ayrıca jsonb_path_query ailesi ve @?, @@ operatörleri aynı yol dilini kullanır.
Bu yazı jsonpath sözdizimini, filtre ifadelerini, lax ve strict modlarını, değişken geçirmeyi, SQL/JSON sorgu fonksiyonlarının ON EMPTY ve ON ERROR davranışlarını, JSON_TABLE ile NESTED PATH kullanımını ve IS JSON doğrulamasını anlatır. ->, ->>, @> operatörleri, jsonb_set ve GIN indeks gibi temel jsonb konuları PostgreSQL JSONB kullanımı yazısında. Örnekler PostgreSQL 18.1 üzerinde çalıştırıldı; serinin geri kalanı için PostgreSQL öğrenme rehberi.
Örnek veri
Her siparişin müşteri, şehir, tarih, kalem listesi ve isteğe bağlı kargo bilgisini tek bir jsonb belgesinde tuttuğumuzu varsayalım. 2 numaralı siparişte kargo bilgisi yok, not alanı ise JSON null:
CREATE TABLE siparis (id int PRIMARY KEY, belge jsonb NOT NULL);
INSERT INTO siparis VALUES
(1, '{"musteri": "Ayşe Yılmaz", "sehir": "İstanbul", "tarih": "2026-03-15",
"kalemler": [{"urun": "Kalem", "adet": 10, "fiyat": 12.5},
{"urun": "Defter", "adet": 3, "fiyat": 45}],
"kargo": {"firma": "Hızlı", "ucret": 0}}'),
(2, '{"musteri": "Mehmet Kaya", "sehir": "Ankara", "tarih": "2026-03-16",
"kalemler": [{"urun": "Çanta", "adet": 1, "fiyat": 850}],
"not": null}'),
(3, '{"musteri": "Zeynep Demir", "sehir": "İzmir", "tarih": "2026-03-18",
"kalemler": [{"urun": "Kalem", "adet": 2, "fiyat": 12.5},
{"urun": "Silgi", "adet": 5, "fiyat": 4}],
"kargo": {"firma": "Ekonomik", "ucret": 39.9}}');jsonpath dilinin temelleri
Bir yol ifadesi her zaman sorgulanan belgeyi temsil eden $ ile başlar. Ardından gelen erişimciler belgede adım adım aşağı iner: .anahtar nesne üyesini, [n] dizi elemanını, [*] dizinin bütün elemanlarını seçer. SQL dizilerinden farklı olarak JSON dizileri sıfırdan başlar. Anahtar adı boşluk içeriyorsa ya da JavaScript tanımlayıcı kurallarına uymuyorsa çift tırnak içine alınır, örneğin $."baslangic zamani". Yol ifadesi SQL içinde tek tırnaklı bir metin olarak yazıldığı için içerideki metin sabitleri çift tırnak kullanır.
Her adım sıfır, bir ya da daha çok sonuç üretebilir. Aşağıdaki sorguda [*] iki kalemi ayrı ayrı seçti, .urun de her birinin ürün adını aldı; jsonb_path_query küme döndüren bir fonksiyon olduğu için iki satır çıktı:
SELECT jsonb_path_query(belge, '$.kalemler[*].urun') AS urun FROM siparis WHERE id = 1; urun
----------
"Kalem"
"Defter"
(2 rows)Satır sayısını değiştirmek istemiyorsanız sonuçları bir dizide toplayan jsonb_path_query_array ya da yalnızca ilk sonucu döndüren jsonb_path_query_first kullanın. Yolun sonuna nokta ile yöntem eklenebilir: .size() dizinin eleman sayısını, .type() değerin tipini, .floor(), .double(), .datetime() gibi yöntemler dönüşüm verir:
SELECT id, jsonb_path_query_array(belge, '$.kalemler[*].urun') AS urunler,
jsonb_path_query_first(belge, '$.kalemler[*].fiyat') AS ilk_fiyat,
jsonb_path_query(belge, '$.kalemler.size()') AS kalem_sayisi
FROM siparis ORDER BY id; id | urunler | ilk_fiyat | kalem_sayisi
----+---------------------+-----------+--------------
1 | ["Kalem", "Defter"] | 12.5 | 2
2 | ["Çanta"] | 850 | 1
3 | ["Kalem", "Silgi"] | 12.5 | 2
(3 rows)Bir metni jsonpath tipine çevirdiğinizde PostgreSQL onu ayrıştırıp normalleştirilmiş biçimde gösterir. Bu, yazdığınız yolun nasıl anlaşıldığını görmenin kolay bir yoludur:
SELECT '$.kalemler[*] ? (@.adet > 2)'::jsonpath AS yol; yol
--------------------------------
$."kalemler"[*]?(@."adet" > 2)
(1 row)Filtre ifadeleri: ? (koşul)

Filtre, SQL'deki WHERE gibi çalışır ve ? (koşul) biçiminde, uygulanacağı adımın hemen arkasına yazılır. Koşulun içinde @ değişkeni o anda değerlendirilen öğeyi temsil eder. Karşılaştırma için ==, !=, <, >= gibi operatörler, mantık için &&, || ve ! kullanılır. Filtrenin hangi adıma uygulandığı sonucu belirler: aşağıda filtre kalem nesnelerine uygulanıyor, sonra filtreden geçen kalemlerin ürün adı alınıyor:
SELECT id, jsonb_path_query(belge, '$.kalemler[*] ? (@.adet >= 5).urun') AS cok_adet
FROM siparis ORDER BY id; id | cok_adet
----+----------
1 | "Kalem"
3 | "Silgi"
(2 rows)2 numaralı sipariş sonuçta yok: jsonb_path_query eşleşme olmayan belge için satır üretmez. Bu, JSONB yazısında gördüğümüz küme döndüren fonksiyonların davranışıyla aynıdır.
Metin filtreleri: like_regex ve starts with
Filtre içinde metin aramak için iki yüklem vardır: like_regex bir düzenli ifadeyle eşleşmeyi, isteğe bağlı flag "i" ile harfe duyarsız olarak sınar; starts with ön ek kontrolü yapar. Belgeler like_regex desenlerinin yorumlanmasında SQL'deki POSIX düzenli ifadelerinden küçük farklar olduğunu belirtir.
SELECT id, jsonb_path_query_array(belge, '$.kalemler[*] ? (@.urun like_regex "^ka" flag "i").urun') AS regex,
jsonb_path_query_array(belge, '$.kalemler[*] ? (@.urun starts with "S").urun') AS baslar
FROM siparis ORDER BY id; id | regex | baslar
----+-----------+-----------
1 | ["Kalem"] | []
2 | [] | []
3 | ["Kalem"] | ["Silgi"]
(3 rows)Değişken geçirmek
Yol içinde $ad biçiminde adlandırılmış değişkenler kullanabilirsiniz. jsonb_path_* fonksiyonlarında değerler üçüncü argüman olarak bir JSON nesnesiyle, SQL/JSON fonksiyonlarında ise PASSING deger AS ad ile verilir. Uygulamadan gelen sınır değerlerini yol metnine birleştirmek yerine bu yolu kullanın:
SELECT id, jsonb_path_exists(belge, '$.kalemler[*] ? (@.fiyat > $alt && @.fiyat < $ust)', '{"alt": 10, "ust": 50}') AS aralikta
FROM siparis ORDER BY id; id | aralikta
----+----------
1 | t
2 | f
3 | t
(3 rows)@? ve @@ operatörleri
WHERE içinde jsonpath kullanmanın iki kısa yolu vardır. @? "yol bir sonuç üretiyor mu?" sorusunu yanıtlar ve filtreli standart yol ifadeleriyle kullanılır. @@ ise bir doğruluk yüklemi bekler; PostgreSQL'in standarda eklediği bu biçimde yolun kendisi $.kalemler[*].fiyat > 500 gibi bir karşılaştırmadır. Belgeler iki biçimin karıştırılmamasını özellikle vurgular: yüklem ifadesi her zaman bir değer döndürdüğü için @? ile anlamsızdır, standart yol ise @@ ile tek bir mantıksal değer üretmediğinde NULL verir.
SELECT id FROM siparis WHERE belge @? '$.kalemler[*] ? (@.urun == "Kalem")' ORDER BY id;
SELECT id FROM siparis WHERE belge @@ '$.kalemler[*].fiyat > 500'; id
----
1
3
(2 rows)
id
----
2
(1 row)Bu iki operatör jsonb sütunundaki GIN indeksini kullanabilir. Belgelere göre GIN, yol ifadesinden erisim_zinciri == sabit biçimindeki koşulları çıkarıp indeks aramasını onlara göre yapar; dolayısıyla eşitlik içeren filtreler indeksten en çok yararlanan sorgulardır.
lax ve strict modları
Yol belgenin gerçek yapısına uymadığında, örneğin dizi olan bir değere nesne erişimcisi uygulandığında bu bir "yapısal hata"dır. Varsayılan lax modunda motor veriyi yola uydurmaya çalışır: dizileri gerektiğinde otomatik olarak açar ya da tek değeri diziye sarar, düzeltemediği hataları sessizce eşleşmesiz sayar. strict modunda ise yapısal hata gerçek bir hataya dönüşür. Yolun başına lax ya da strict yazarak modu seçersiniz:
SELECT jsonb_path_query(belge, 'lax $.kalemler.urun') AS lax_mod FROM siparis WHERE id = 1;
SELECT jsonb_path_query(belge, 'strict $.kalemler.urun') AS strict_mod FROM siparis WHERE id = 1; lax_mod
----------
"Kalem"
"Defter"
(2 rows)
ERROR: jsonpath member accessor can only be applied to an objectLax modunda kalemler dizisi kendiliğinden açıldı ve [*] yazmadan da ürünler geldi. Strict modda aynı sonucu almak için diziyi [*] ile açıkça açmanız gerekir. Lax modun bu kolaylığı sürprizlere de yol açabilir; belgeler .** (her seviyeye inen) erişimcisinin lax modda değerleri iki kez seçebildiğini gösterir ve bu erişimcinin yalnızca strict modda kullanılmasını önerir.
Hataları susturmanın bir yolu da jsonb_path_* fonksiyonlarının silent parametresidir. Doğru verildiğinde eksik alan, beklenmeyen tip, tarih ve sayı hataları bastırılır; bu, @? ve @@ operatörlerinin zaten yaptığı şeydir. Kargo bilgisi olmayan 2 numaralı siparişte strict yol hata vermek yerine NULL döndürdü:
SELECT id, jsonb_path_query_first(belge, 'strict $.kargo.firma', silent => true) AS sessiz FROM siparis ORDER BY id; id | sessiz
----+------------
1 | "Hızlı"
2 |
3 | "Ekonomik"
(3 rows)Tarihlerle çalışmak: .datetime()
JSON'da tarih diye bir tip yoktur, tarihler metin olarak gelir. .datetime() yöntemi bir metni tarih/saat değerine çevirir ve böylece yol içinde tarih karşılaştırması yapılabilir. İsteğe bağlı bir şablon argümanı alır; belgelere göre ayrıştırma to_timestamp fonksiyonunun kurallarıyla yapılır, yalnızca eşleşmeyen kalıplara izin verilmemesi ve kabul edilen ayırıcıların sınırlı olması gibi birkaç istisna vardır. Saat dilimine bağlı dönüşüm gerektiren karşılaştırmalar için fonksiyonların _tz ile biten sürümleri (jsonb_path_exists_tz gibi) vardır.
SELECT id, jsonb_path_query_first(belge, '$.tarih.datetime() ? (@ >= "2026-03-16".datetime())') AS sonra
FROM siparis ORDER BY id; id | sonra
----+--------------
1 |
2 | "2026-03-16"
3 | "2026-03-18"
(3 rows)Tarih tipleri ve şablon kalıpları PostgreSQL tarih ve saat yazısında ayrıntılı olarak anlatılıyor.
JSON_VALUE, JSON_QUERY ve JSON_EXISTS

SQL standardındaki üç sorgu fonksiyonu bir belge ve bir yol alır, değişkenleri PASSING ile kabul eder ve boş sonuç ile hata durumunda ne yapılacağını ON EMPTY ve ON ERROR yan tümceleriyle belirlemenizi sağlar.
| Fonksiyon | Döndürdüğü | Varsayılan ON EMPTY | Varsayılan ON ERROR |
|---|---|---|---|
| JSON_EXISTS | boolean | uygulanmaz | FALSE |
| JSON_VALUE | tek skaler, varsayılan text | NULL | NULL |
| JSON_QUERY | nesne, dizi ya da skaler, varsayılan jsonb | NULL | NULL |
JSON_VALUE tek bir skaler değer bekler ve RETURNING ile istediğiniz SQL tipine çevirir; metin değerlerin tırnakları her zaman kaldırılır. DEFAULT ... ON EMPTY eksik alanlar için yedek değer verir:
SELECT id,
JSON_VALUE(belge, '$.musteri') AS musteri,
JSON_VALUE(belge, '$.kargo.ucret' RETURNING numeric DEFAULT 0 ON EMPTY) AS kargo_ucret,
JSON_VALUE(belge, '$.tarih' RETURNING date) AS tarih,
JSON_EXISTS(belge, '$.kargo') AS kargolu
FROM siparis ORDER BY id; id | musteri | kargo_ucret | tarih | kargolu
----+--------------+-------------+------------+---------
1 | Ayşe Yılmaz | 0 | 2026-03-15 | t
2 | Mehmet Kaya | 0 | 2026-03-16 | f
3 | Zeynep Demir | 39.9 | 2026-03-18 | t
(3 rows)1 numaralı siparişteki 0 gerçek değerdir, 2 numaralıdaki 0 ise DEFAULT ile gelen yedek değerdir; ikisini ayırt etmeniz gerekiyorsa JSON_EXISTS sütununa bakın ya da yedek değer kullanmayın.
Sessiz NULL tuzağı
Bu fonksiyonların en çok şaşırtan yanı, varsayılan NULL ON ERROR davranışıdır: bir hata oluştuğunda size hata yerine NULL döner. Örneğin JSON_VALUE birden çok değer üreten bir yolla çağrılırsa sonuç sessizce NULL olur. Geliştirme sırasında ERROR ON ERROR ekleyerek gerçek nedeni görebilirsiniz:
SELECT JSON_VALUE(belge, '$.kalemler[*].urun') AS coklu_sessiz FROM siparis WHERE id = 1;
SELECT JSON_VALUE(belge, '$.kalemler[*].urun' ERROR ON ERROR) FROM siparis WHERE id = 1; coklu_sessiz
--------------
(1 row)
ERROR: JSON path expression in JSON_VALUE must return single scalar itemJSON_QUERY ve WRAPPER, QUOTES
JSON_QUERY nesne ya da dizi döndürmek için kullanılır. Yol birden çok değer üretiyorsa onları geçerli bir JSON dizisine sarmak için WITH WRAPPER gerekir; WITH CONDITIONAL WRAPPER yalnızca birden çok değer olduğunda sarar. Skaler metin sonuçlar varsayılan olarak tırnaklı döner (KEEP QUOTES); OMIT QUOTES tırnakları kaldırır:
SELECT id,
JSON_QUERY(belge, '$.kargo') AS kargo,
JSON_QUERY(belge, '$.kalemler[*].urun' WITH WRAPPER) AS urunler,
JSON_QUERY(belge, '$.kalemler[*].urun' WITH CONDITIONAL WRAPPER) AS kosullu,
JSON_QUERY(belge, '$.musteri') AS tirnakli,
JSON_QUERY(belge, '$.musteri' OMIT QUOTES) AS tirnaksiz
FROM siparis ORDER BY id; id | kargo | urunler | kosullu | tirnakli | tirnaksiz
----+--------------------------------------+---------------------+---------------------+----------------+-----------
1 | {"firma": "Hızlı", "ucret": 0} | ["Kalem", "Defter"] | ["Kalem", "Defter"] | "Ayşe Yılmaz" |
2 | | ["Çanta"] | "Çanta" | "Mehmet Kaya" |
3 | {"firma": "Ekonomik", "ucret": 39.9} | ["Kalem", "Silgi"] | ["Kalem", "Silgi"] | "Zeynep Demir" |
(3 rows)Son sütun boş geldi; bu yine sessiz NULL tuzağıdır. JSON_QUERY varsayılan olarak jsonb döndürür, tırnakları atılmış Ayşe Yılmaz ise geçerli bir JSON değeri değildir; dönüşüm hatası NULL ON ERROR ile NULL'a çevrildi. Tırnaksız metin istiyorsanız dönüş tipini metin yapın ya da doğrudan JSON_VALUE kullanın:
SELECT JSON_QUERY(jsonb '{"musteri": "Ayşe Yılmaz"}', '$.musteri' OMIT QUOTES) AS jsonb_donus,
JSON_QUERY(jsonb '{"musteri": "Ayşe Yılmaz"}', '$.musteri' RETURNING text OMIT QUOTES) AS text_donus; jsonb_donus | text_donus
-------------+-------------
| Ayşe Yılmaz
(1 row)Belgelerdeki bir notu da unutmayın: yol JSON null ürettiğinde JSON_VALUE SQL NULL döndürür, JSON_QUERY ise JSON null değerini olduğu gibi verir. 2 numaralı siparişteki not alanında ilk sütun boş, ikinci sütun null çıktı. Ayrıca bağlam öğesi metin olarak verilip jsonb'ye çevrilirken oluşan ayrıştırma hataları ON ERROR yan tümcesinden bağımsız olarak her zaman hata olarak bildirilir.
SELECT JSON_VALUE(belge, '$.not') AS value_null, JSON_QUERY(belge, '$.not') AS query_null
FROM siparis WHERE id = 2;
SELECT JSON_VALUE(belge, '$.kalemler[0].adet' RETURNING int) * 2 AS iki_kat,
JSON_EXISTS(belge, 'strict $.kalemler[5]') AS sessiz_false,
JSON_EXISTS(belge, 'strict $.kalemler[*] ? (@.fiyat > $f)' PASSING 40 AS f) AS passing_ile
FROM siparis WHERE id = 1; value_null | query_null
------------+------------
| null
(1 row)
iki_kat | sessiz_false | passing_ile
---------+--------------+-------------
20 | f | t
(1 row)İkinci sorguda strict modda sınır dışı bir dizi indeksi hata üretti, ama JSON_EXISTS varsayılan FALSE ON ERROR ile bunu yanlış olarak raporladı. Hatayı görmek isteseydiniz ERROR ON ERROR yazmanız gerekirdi.
JSON_TABLE: JSON dizisini tabloya çevirmek
JSON_TABLE, FROM içinde kullanılan ve JSON verisini gerçek bir tablo gibi sunan fonksiyondur. İlk yol ifadesi satır desenini belirler: o yolun ürettiği her değer bir satır olur. COLUMNS yan tümcesi her sütun için tipi ve satır desenine göre göreli bir yolu tanımlar. FOR ORDINALITY 1'den başlayan sıra numarası, EXISTS PATH ise bir yolun var olup olmadığını gösteren mantıksal sütun üretir. Üretilen satırlar kaynak satıra yanal (lateral) olarak bağlandığı için ayrıca JOIN koşulu yazmanız gerekmez:
SELECT s.id, jt.*
FROM siparis s,
JSON_TABLE(s.belge, '$.kalemler[*]'
COLUMNS (
sira FOR ORDINALITY,
urun text PATH '$.urun',
adet int PATH '$.adet',
fiyat numeric PATH '$.fiyat',
indirimli boolean EXISTS PATH '$.indirim'
)) AS jt
ORDER BY s.id, jt.sira; id | sira | urun | adet | fiyat | indirimli
----+------+--------+------+-------+-----------
1 | 1 | Kalem | 10 | 12.5 | f
1 | 2 | Defter | 3 | 45 | f
2 | 1 | Çanta | 1 | 850 | f
3 | 1 | Kalem | 2 | 12.5 | f
3 | 2 | Silgi | 5 | 4 | f
(5 rows)Bu noktadan sonra JSON verisi sıradan bir tablodur: üzerinde gruplama, sıralama ve birleştirme yapabilirsiniz. Ürün bazında ciro raporu tek sorguyla çıkar:
SELECT jt.urun, sum(jt.adet) AS toplam_adet, sum(jt.adet * jt.fiyat) AS ciro
FROM siparis s,
JSON_TABLE(s.belge, '$.kalemler[*]' COLUMNS (urun text PATH '$.urun', adet int PATH '$.adet', fiyat numeric PATH '$.fiyat')) AS jt
GROUP BY jt.urun ORDER BY ciro DESC; urun | toplam_adet | ciro
--------+-------------+-------
Çanta | 1 | 850
Kalem | 12 | 150.0
Defter | 3 | 135
Silgi | 5 | 20
(4 rows)NESTED PATH ile iç içe seviyeler
Üst seviye alanları ve iç içe bir diziyi aynı sorguda almak için NESTED PATH kullanılır. İç içe yan tümcenin ürettiği "çocuk satırlar" üst satırla birleştirilir. PATH yazmazsanız sütun adı yol olarak kabul edilir (aşağıdaki sehir sütunu $.sehir yolunu kullanıyor). Sütun yolları aritmetik de içerebilir:
SELECT jt.*
FROM siparis s,
JSON_TABLE(s.belge, '$'
COLUMNS (
musteri text PATH '$.musteri',
sehir text,
kargo_firma text PATH '$.kargo.firma' DEFAULT 'yok' ON EMPTY,
NESTED PATH '$.kalemler[*]' COLUMNS (
urun text PATH '$.urun',
tutar numeric PATH '$.adet * $.fiyat'
)
)) AS jt
ORDER BY musteri, urun; musteri | sehir | kargo_firma | urun | tutar
--------------+----------+-------------+--------+-------
Ayşe Yılmaz | İstanbul | Hızlı | Defter | 135
Ayşe Yılmaz | İstanbul | Hızlı | Kalem | 125.0
Mehmet Kaya | Ankara | yok | Çanta | 850
Zeynep Demir | İzmir | Ekonomik | Kalem | 25.0
Zeynep Demir | İzmir | Ekonomik | Silgi | 20
(5 rows)Aynı seviyede birden çok NESTED PATH yazarsanız belgelere göre bunlar "kardeş" sayılır ve satırları UNION ile birleştirilir, yani birbirleriyle çapraz çarpılmazlar. Sütun düzeyindeki ON EMPTY/ON ERROR davranışı JSON_VALUE ve JSON_QUERY ile aynıdır; tablonun sonuna yazılan ERROR ON ERROR ya da EMPTY ON ERROR ise yalnızca üst seviye yolun hatalarını etkiler. JSON_TABLE SELECT dışında UPDATE, DELETE ve MERGE içinde de veri kaynağı olarak kullanılabilir. Gruplama için GROUP BY ve aggregate, yanal birleşme için JOIN ve LATERAL yazılarına bakabilirsiniz.
IS JSON ile doğrulama
IS JSON yüklemi bir metnin JSON olarak ayrıştırılıp ayrıştırılamayacağını hata üretmeden sınar. OBJECT, ARRAY, SCALAR ile tür, WITH UNIQUE KEYS ile tekrarlanan anahtar kontrolü eklenebilir:
SELECT v AS deger, v IS JSON AS json_mu, v IS JSON OBJECT AS nesne_mi, v IS JSON ARRAY AS dizi_mi,
v IS JSON SCALAR AS skaler_mi, v IS JSON WITH UNIQUE KEYS AS tekil_anahtar
FROM (VALUES ('{"a": 1}'), ('[1, 2]'), ('"metin"'), ('{"a": 1, "a": 2}'), ('{bozuk}')) AS t(v); deger | json_mu | nesne_mi | dizi_mi | skaler_mi | tekil_anahtar
------------------+---------+----------+---------+-----------+---------------
{"a": 1} | t | t | f | f | t
[1, 2] | t | f | t | f | t
"metin" | t | f | f | t | t
{"a": 1, "a": 2} | t | t | f | f | f
{bozuk} | f | f | f | f | f
(5 rows)Gelen ham veriyi metin olarak saklayıp yine de yapısını zorlamak isterseniz bu yüklemi bir CHECK kısıtında kullanabilirsiniz:
CREATE TABLE gelen_istek (id int, govde text CHECK (govde IS JSON OBJECT));
INSERT INTO gelen_istek VALUES (1, '{"olay": "giris"}');
INSERT INTO gelen_istek VALUES (2, '[1, 2]');ERROR: new row for relation "gelen_istek" violates check constraint "gelen_istek_govde_check"
DETAIL: Failing row contains (2, [1, 2]).Kısıtların genel kullanımı PRIMARY KEY, FOREIGN KEY ve kısıtlar yazısında.
Hangi aracı ne zaman kullanmalı?

| İhtiyaç | Uygun araç |
|---|---|
| Tek bir alanı SQL tipinde almak | JSON_VALUE ya da ->> ve tip dönüşümü |
| Nesne ya da dizi parçası almak | JSON_QUERY ya da -> |
| WHERE içinde koşullu varlık testi | @? ya da JSON_EXISTS |
| Yüklem ile filtre | @@ ya da jsonb_path_match |
| Eşleşen bütün değerleri almak | jsonb_path_query, jsonb_path_query_array |
| JSON dizisini satırlara açmak | JSON_TABLE ya da jsonb_array_elements |
| Metnin geçerli JSON olduğunu sınamak | IS JSON |
Sık yapılan hatalar
JSON_VALUEveJSON_QUERYsonuçlarındaki beklenmeyen NULL'ları veri eksikliği sanmak: çoğu zaman sessizce yutulan bir hatadır.ERROR ON ERRORile test edin.JSON_VALUEile dizi ya da nesne almaya çalışmak; bunun içinJSON_QUERY.- Varsayılan
jsonbdönüşüyleOMIT QUOTESkullanıp NULL almak;RETURNING textekleyin. - Filtreyi yanlış adıma yazmak:
$.kalemler[*].urun ? (@.adet > 2)ürün adı üzerindeadetarar ve hiçbir şey bulmaz; filtre kalem nesnesinden sonra gelmelidir. @@ile standart filtreli yol,@?ile yüklem ifadesi kullanmak.- Lax modda
.**kullanıp tekrarlanan sonuçlar almak; bu erişimci için strict mod. - Kullanıcı girdisini yol metnine birleştirmek yerine
PASSINGya davarsile değişken geçirmemek.
Sık Sorulan Sorular
JSON_VALUE ile ->> arasında ne fark var?
Basit bir anahtar için ikisi de metin döndürür. JSON_VALUE SQL standardıdır, jsonpath filtrelerini ve değişkenleri destekler, RETURNING ile tip dönüşümünü ve ON EMPTY/ON ERROR ile eksik ve hatalı veriyi tek ifadede yönetir. ->> daha kısadır ve hata vermeden NULL döndürür.
JSON_TABLE ile jsonb_array_elements arasında nasıl seçim yaparım?
Bir diziyi yalnızca satırlara açıp bir iki alan alacaksanız jsonb_array_elements yeterlidir. Çok sayıda tipli sütun, iç içe seviyeler, sıra numarası ve eksik alan için yedek değer gerekiyorsa JSON_TABLE tek bir tanımla daha okunaklı bir sorgu verir.
jsonpath sorguları indeks kullanır mı?
@? ve @@ operatörleri jsonb üzerindeki GIN indeksini kullanabilir. Belgelere göre jsonb_ops operatör sınıfı .* ve .** erişimcilerini de destekler, jsonb_path_ops desteklemez. İndeks türleri için PostgreSQL indeks türleri.
PostgreSQL 18 düzeltme sürümlerinde SQL/JSON ile ilgili ne değişti?
PostgreSQL 18.6 sürüm notları, ON EMPTY/ON ERROR içindeki DEFAULT değerlerinin doğru tip niteleyicisine dönüştürülmesi, jsonpath .decimal() yönteminin hatalı hassasiyet ya da ölçekte sert hata vermemesi ve IS JSON ile ilgili bir çökme gibi düzeltmeler içerir. Bu yüzden kullandığınız 18.x sürümünün güncel olması önerilir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · PostgreSQL JSONB kullanımı · array (dizi) tipi · tarih ve saat · GROUP BY ve aggregate · JOIN ve LATERAL · CSV ve JSON dönüşümü