Eu tenho uma tabela, persons
que contém duas colunas, uma id
e uma data
coluna baseada em JSONB (esta tabela foi criada apenas para fins de demonstração para brincar com o suporte a JSON do PostgreSQL).
Agora, suponha que ele contenha dois registros:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Agora, suponho que eu queira obter o nome de todas as pessoas com mais de 25 anos. O que tentei é:
select data->'name' as name from persons where data->'age' > 25
Infelizmente, isso resulta em um erro. Eu posso resolvê-lo usando em ->>
vez de ->
, mas as comparações não funcionam mais como o esperado, pois não são comparados os números, mas suas representações como seqüências de caracteres:
select data->'name' as name from persons where data->>'age' > '25'
Eu então descobri que realmente posso resolver o problema usando ->
e convertido para int
:
select data->'name' as name from persons where cast(data->'age' as int) > 25
Isso funciona, mas não é tão bom que eu precise saber o tipo real (o tipo de age
documento JSON é number
assim mesmo, então por que o PostgreSQL não pode descobrir isso sozinho?).
Eu então descobri que, se eu converter manualmente para o text
uso da ::
sintaxe, tudo funcionará conforme o esperado também - embora agora possamos comparar as strings novamente.
select data->'name' as name from persons where data->'age'::text > '25'
Se eu tentar isso com o nome em vez da idade, não funcionará:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Isso resulta em um erro:
sintaxe de entrada inválida para o tipo json
Obviamente, não tenho nada aqui. Infelizmente, é muito difícil encontrar exemplos reais do uso de JSON com o PostgreSQL.
Alguma dica?
fonte
data->'name'::text
, você está convertendo a'name'
string em texto, não no resultado. Você não recebe um erro ao comparar'25'
porque25
é um literal JSON válido; masJenny
não é (embora"Jenny"
seria).'Jenny'
com'"Jenny"'
.Respostas:
Isso não funciona porque está tentando converter um
jsonb
valor parainteger
.Isso realmente funcionaria:
Ou mais curto:
E isto:
Parece que a confusão com os dois operadores
->
e->>
e precedência do operador . O elenco::
se liga mais forte que os operadores json (b).Descobrir o tipo dinamicamente
Esta é a parte mais interessante da sua pergunta:
SQL é uma linguagem estritamente digitada, não permite que a mesma expressão seja avaliada
integer
em uma linha etext
na seguinte. Mas como você está interessado apenas noboolean
resultado do teste, é possível contornar essa restrição com umaCASE
expressão que bifurca dependendo do resultado dejsonb_typeof()
:Uma cadeia de caracteres sem tipo literal à direita do
>
operador é coagida automaticamente ao respectivo tipo de valor à esquerda. Se você colocar um valor digitado lá, o tipo deverá corresponder ou será necessário convertê-lo explicitamente - a menos que exista uma conversão implícita adequada registrada no sistema.Se você souber que todos os valores numéricos são realmente
integer
, também pode:fonte