Mam tabelę, persons
która zawiera dwie kolumny id
oraz data
kolumnę opartą na JSONB (ta tabela została właśnie stworzona w celach demonstracyjnych do zabawy z obsługą JSON w PostgreSQL).
Teraz przypuszcza, że zawiera dwa rekordy:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Teraz przypuszczam, że chcę uzyskać imię każdej osoby w wieku powyżej 25 lat. Próbowałem:
select data->'name' as name from persons where data->'age' > 25
Niestety powoduje to błąd. Mogę rozwiązać to za pomocą ->>
zamiast ->
, ale wtedy porównania nie działają już zgodnie z oczekiwaniami, ponieważ nie porównuje się liczb, ale ich reprezentacje jako ciągi znaków:
select data->'name' as name from persons where data->>'age' > '25'
Potem zorientowałem się, że mogę rozwiązać problem, używając ->
i obsady int
:
select data->'name' as name from persons where cast(data->'age' as int) > 25
To działa, ale nie jest miło, że muszę znać rzeczywisty typ (typ age
dokumentu JSON jest number
zresztą, więc dlaczego PostgreSQL nie może tego sam zrozumieć?).
Potem zorientowałem się, że jeśli ręcznie przekonwertuję na text
użycie ::
składni, wszystko też działa zgodnie z oczekiwaniami - chociaż teraz ponownie porównujemy łańcuchy.
select data->'name' as name from persons where data->'age'::text > '25'
Jeśli następnie wypróbuję to z nazwą zamiast wieku, to nie działa:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Powoduje to błąd:
niepoprawna składnia wejściowa dla typu json
Najwyraźniej nic tu nie rozumiem. Niestety, ciężko jest znaleźć rzeczywiste przykłady użycia JSON z PostgreSQL.
Jakieś wskazówki?
źródło
data->'name'::text
rzutujesz'name'
ciąg na tekst, a nie wynik. Nie pojawia się błąd przy porównywaniu,'25'
ponieważ25
jest to prawidłowy literał JSON; aleJenny
nie jest (chociaż"Jenny"
byłoby).'Jenny'
się'"Jenny"'
.Odpowiedzi:
To nie działa, ponieważ próbuje rzucić
jsonb
wartość nainteger
.To faktycznie działałoby:
Lub krócej:
I to:
Wygląda na to zamieszanie z dwoma operatorami
->
i->>
oraz pierwszeństwa operatora . Rzutowanie::
wiąże się silniej niż operatory json (b).Dobierz typ dynamicznie
To jest bardziej interesująca część twojego pytania:
SQL jest językiem ściśle wpisanym, nie pozwala na ocenę tego samego wyrażenia
integer
w jednym wierszu itext
w następnym. Ale ponieważ interesuje Cię tylkoboolean
wynik testu, możesz obejść to ograniczenie zCASE
wyrażeniem, które rozwidla się w zależności od wynikujsonb_typeof()
:Niepisany ciąg literału po prawej stronie
>
operatora jest automatycznie wymuszany na odpowiednim typie wartości po lewej stronie. Jeśli umieścisz tam wpisaną wartość, typ musi być zgodny lub musisz rzucić ją jawnie - chyba że w systemie zarejestrowano odpowiednią ukrytą rzutowanie.Jeśli wiesz, że wszystkie wartości liczbowe są w rzeczywistości
integer
, możesz również:źródło