PostgreSQL'de JSONB'yi sorgulama


14

personsİki sütun içeren bir tablo var , bir idve bir JSONB tabanlı datasütun (bu tablo sadece gösteri amaçlı PostgreSQL'in JSON desteği ile oynamak için yapılmıştır).

Şimdi, iki kayıt içerdiğini varsayalım:

1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }

Şimdi, 25 yaşından büyük herkesin adını almak istiyorum varsayalım.

select data->'name' as name from persons where data->'age' > 25

Ne yazık ki, bu bir hatayla sonuçlanır. Bunu ->>yerine kullanarak çözebilirim ->, ancak daha sonra karşılaştırmalar beklendiği gibi çalışmaz, çünkü sayılar karşılaştırılmaz, ancak dizeler olarak gösterimleri:

select data->'name' as name from persons where data->>'age' > '25'

Daha sonra sorunu kullanarak ->ve bir döküm kullanarak gerçekten çözebileceğimi anladım int:

select data->'name' as name from persons where cast(data->'age' as int) > 25

Bu işe yarıyor, ama gerçek türü bilmek zorunda değilim o kadar güzel değil ( ageJSON belgesindeki türü numberzaten, bu yüzden PostgreSQL neden bunu kendi başına anlayamıyor?).

Daha sonra text, ::sözdizimini kullanarak manuel olarak dönüştürdüğümde , şimdi dizeleri tekrar karşılaştırmamıza rağmen, her şeyin de beklendiği gibi çalıştığını anladım .

select data->'name' as name from persons where data->'age'::text > '25'

Daha sonra bunu yaş yerine adıyla denerseniz, işe yaramaz:

select data->'name' as name from persons where data->'name'::text > 'Jenny'

Bu bir hatayla sonuçlanır:

json türü için geçersiz giriş sözdizimi

Açıkçası burada bir şey bulamıyorum. Ne yazık ki, PostgreSQL ile JSON kullanmanın gerçek dünyadaki örneklerini bulmak oldukça zor.

İpucu var mı?


1
İçinde data->'name'::text, 'name'dizeyi sonuca değil metne döküyorsunuz. Sen karşılaştırarak bir hata alamadım '25'çünkü 25geçerli bir JSON değişmezi olduğu; ama Jennydeğil (olmasına rağmen "Jenny").
chirlu

Teşekkürler, çözüm bu :-). Ben karıştı 'Jenny'ile '"Jenny"'.
Golo Roden

Yanıtlar:


15

Bu işe yaramıyor çünkü jsonbdeğer vermeye çalışıyor integer.

select data->'name' as name from persons where cast(data->'age' as int) > 25

Bu aslında işe yarar:

SELECT data->'name' AS name FROM persons WHERE cast(data->>'age' AS int) > 25;

Veya daha kısa:

SELECT data->'name' AS name FROM persons WHERE (data->>'age')::int > 25;

Ve bu:

SELECT data->'name' AS name FROM persons WHERE data->>'name' > 'Jenny';

İki ile karışıklık gibi görünüyor operatörler ->ve->> ve operatör önceliği . Döküm ::json (b) operatörlerinden daha güçlü bağlanır.

Türü dinamik olarak anlama

Sorunuzun daha ilginç kısmı:

JSON belgesindeki yaş türü zaten sayıdır, neden PostgreSQL bunu kendi başına anlayamıyor?

SQL tam olarak yazılan bir dildir, aynı ifadenin integerbir satırda ve bir textsonraki satırda değerlendirilmesine izin vermez . Ancak yalnızca booleantestin sonucuyla ilgilendiğiniz için, bu kısıtlamaya CASE, aşağıdakilerin sonucuna bağlı olarak çatallanan bir ifade ile ulaşabilirsiniz jsonb_typeof():

SELECT data->'name'
FROM   persons
WHERE  CASE jsonb_typeof(data->'age')
        WHEN 'number'  THEN (data->>'age')::numeric > '25' -- treated as numeric
        WHEN 'string'  THEN data->>'age' > 'age_level_3'   -- treated as text
        WHEN 'boolean' THEN (data->>'age')::bool           -- use boolean directly (example)
        ELSE FALSE                                         -- remaining: array, object, null
       END;

>Operatörün sağındaki türlenmemiş bir dize , otomatik olarak soldaki değerin ilgili türüne zorlanır. Buraya yazılan bir değer koyarsanız, sistemde kayıtlı örtülü bir döküm yoksa türün eşleşmesi veya açıkça belirtmeniz gerekir.

Tüm sayısal değerlerin aslında olduğunu biliyorsanız , şunları da yapabilirsiniz:integer

... (data->>'age')::int > 25 ...

select deyiminin yukarıdaki karşılaştırması için sqlalchemy çekirdek ifadesi nedir örn. s = seçin ([sorunlar]). burada (issue.c.id == mid) .select_from (sorunlar, ..... dış birleşim (issue.c.data ['type_id'] == mtypes.c.id) ) ... İşte sorunlar.c.data jsonb veri türü ve tamsayı türü mtypes.c.id ile karşılaştırılıyor
user956424
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.