Ich habe eine Tabelle, persons
die zwei Spalten enthält, eine id
und eine JSONB-basierte data
Spalte (diese Tabelle wurde nur zu Demonstrationszwecken erstellt, um mit der JSON-Unterstützung von PostgreSQL herumzuspielen).
Angenommen, es enthält zwei Datensätze:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Angenommen, ich möchte den Namen jeder Person erfahren, die älter als 25 Jahre ist. Was ich versucht habe, ist:
select data->'name' as name from persons where data->'age' > 25
Dies führt leider zu einem Fehler. Ich kann es lösen, indem ich ->>
anstelle von verwende ->
, aber dann funktionieren Vergleiche nicht mehr wie erwartet, da nicht die Zahlen verglichen werden, sondern ihre Darstellungen als Zeichenfolgen:
select data->'name' as name from persons where data->>'age' > '25'
Ich fand dann heraus, dass ich das Problem tatsächlich lösen kann, indem ich ->
eine Besetzung verwende, um int
:
select data->'name' as name from persons where cast(data->'age' as int) > 25
Das funktioniert, aber es ist nicht so schön, dass ich den tatsächlichen Typ kennen muss (der Typ age
im JSON-Dokument ist number
sowieso. Warum kann PostgreSQL das nicht selbst herausfinden?).
Ich habe dann herausgefunden, dass, wenn ich manuell in text
die ::
Syntax konvertiere , auch alles wie erwartet funktioniert - obwohl wir jetzt wieder Zeichenfolgen vergleichen.
select data->'name' as name from persons where data->'age'::text > '25'
Wenn ich das dann mit dem Namen anstelle des Alters versuche, funktioniert es nicht:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Dies führt zu einem Fehler:
ungültige Eingabesyntax für Typ json
Ganz offensichtlich bekomme ich hier nichts. Leider ist es ziemlich schwierig, Beispiele für die Verwendung von JSON mit PostgreSQL in der Praxis zu finden.
Irgendwelche Hinweise?
quelle
data->'name'::text
wandeln Sie die'name'
Zeichenfolge in Text um, nicht in das Ergebnis. Beim Vergleich mit wird kein Fehler angezeigt,'25'
da25
es sich um ein gültiges JSON-Literal handelt. ist aberJenny
nicht (obwohl"Jenny"
wäre).'Jenny'
mit'"Jenny"'
.Antworten:
Dies funktioniert nicht, weil versucht wird, einen
jsonb
Wert auf zu setzeninteger
.Das würde tatsächlich funktionieren:
Oder kürzer:
Und das:
Scheint wie Verwechslung mit den beiden Operatoren
->
und->>
und Operator Vorrang . Die Besetzung::
bindet stärker als die json (b) -Operatoren.Typ dynamisch herausfinden
Dies ist der interessantere Teil Ihrer Frage:
SQL ist eine streng typisierte Sprache, bei der nicht derselbe Ausdruck
integer
in einer Zeile undtext
in der nächsten ausgewertet werden kann . Da Sie jedoch nurboolean
am Testergebnis interessiert sind , können Sie diese Einschränkung mit einemCASE
Ausdruck umgehen, der sich abhängig vom Ergebnis vonjsonb_typeof()
:Ein untypisiertes Zeichenfolgenliteral rechts vom
>
Operator wird automatisch zum jeweiligen Typ des Werts links gezwungen. Wenn Sie dort einen typisierten Wert eingeben, muss der Typ übereinstimmen oder explizit umgewandelt werden - es sei denn, im System ist eine angemessene implizite Umwandlung registriert.Wenn Sie wissen, dass alle numerischen Werte tatsächlich sind
integer
, können Sie auch:quelle