J'ai une table, persons
qui contient deux colonnes, une id
et une data
colonne basée sur JSONB (cette table vient d'être créée à des fins de démonstration pour jouer avec le support JSON de PostgreSQL).
Maintenant, supposons qu'il contienne deux enregistrements:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Maintenant, je suppose que je veux obtenir le nom de toute personne âgée de plus de 25 ans. Ce que j'ai essayé, c'est:
select data->'name' as name from persons where data->'age' > 25
Malheureusement, cela entraîne une erreur. Je peux le résoudre en utilisant ->>
au lieu de ->
, mais les comparaisons ne fonctionnent plus comme prévu, car non les chiffres sont comparés, mais leurs représentations sous forme de chaînes:
select data->'name' as name from persons where data->>'age' > '25'
J'ai ensuite compris que je pouvais réellement résoudre le problème en utilisant ->
et un cast pour int
:
select data->'name' as name from persons where cast(data->'age' as int) > 25
Cela fonctionne, mais ce n'est pas si agréable que je dois connaître le type réel (le type de age
dans le document JSON estnumber
toute façon, alors pourquoi PostgreSQL ne peut-il pas le comprendre par lui-même?).
J'ai ensuite compris que si je convertis manuellement en text
utilisant la ::
syntaxe, tout fonctionne aussi comme prévu - bien que nous comparions à nouveau les chaînes.
select data->'name' as name from persons where data->'age'::text > '25'
Si j'essaye ensuite avec le nom au lieu de l'âge, cela ne fonctionne pas:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Il en résulte une erreur:
syntaxe d'entrée non valide pour le type json
De toute évidence, je ne reçois pas quelque chose ici. Malheureusement, il est assez difficile de trouver des exemples concrets d'utilisation de JSON avec PostgreSQL.
Des indices?
la source
data->'name'::text
, vous transformez la'name'
chaîne en texte, pas le résultat. Vous n'obtenez pas d'erreur lors de la comparaison avec'25'
car25
est un littéral JSON valide; maisJenny
n'est pas (bien que ce"Jenny"
serait).'Jenny'
avec'"Jenny"'
.Réponses:
Cela ne fonctionne pas car il essaie de convertir une
jsonb
valeur eninteger
.Cela fonctionnerait en fait:
Ou plus court:
Et ça:
Semble comme une confusion avec les deux opérateurs
->
et->>
et la priorité des opérateurs . Le casting::
plus fort que les opérateurs json (b).Comprendre le type dynamiquement
Voici la partie la plus intéressante de votre question:
SQL est un langage strictement typé, il ne permet pas à la même expression d'évaluer
integer
dans une ligne ettext
dans la suivante. Mais comme vous n'êtes intéressé que par leboolean
résultat du test, vous pouvez contourner cette restriction avec unCASE
expression qui bifurque en fonction du résultat dejsonb_typeof()
:Une chaîne de caractères non typée à droite de la
>
opérateur est contraint automatiquement au type respectif de la valeur à gauche. Si vous y mettez une valeur typée, le type doit correspondre ou vous devez le caster explicitement - à moins qu'il n'y ait un cast implicite adéquat enregistré dans le système.Si vous savez que toutes les valeurs numériques sont réellement
integer
, vous pouvez également:la source