在PostgreSQL中查询JSONB


14

我有一个表,persons其中包含两列,一个id和一个基于JSONB的data列(此表仅出于演示目的而制作,可以与PostgreSQL的JSON支持一起使用)。

现在,假设它包含两个记录:

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

现在,假设我想获得每个25岁以上的人的名字。我尝试过的是:

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

不幸的是,这会导致错误。我可以使用->>代替来解决它->,但是比较不会再按预期进行,因为不是比较数字,而是将它们表示为字符串:

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

然后,我发现实际上可以使用->和强制转换为解决此问题int

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

这行得通,但是我必须知道实际的类型不是很好(ageJSON文档中的类型number仍然是,所以PostgreSQL为什么不能自己弄清楚呢?)。

然后,我发现,如果我手动转换为text使用::语法,那么一切也会按预期工作-尽管我们现在再次比较字符串。

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

如果我再尝试使用名称而不是年龄来尝试,则不起作用:

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

这会导致错误:

json类型的输入语法无效

很明显,我在这里什么都没有。不幸的是,很难找到在PostgreSQL中使用JSON的任何实际示例。

有什么提示吗?


1
在中data->'name'::text,您正在将'name'字符串转换为文本,而不是结果。与进行比较时不会出现错误,'25'因为25它是有效的JSON文字;但Jenny不是(尽管"Jenny"会)。
chirlu '16

谢谢,这就是解决方案:-)。我困惑'Jenny''"Jenny"'
Golo Roden

Answers:


15

这不起作用,因为它正在尝试将jsonb值强制转换为integer

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

实际上可以工作:

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

或更短:

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

和这个:

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

似乎与两个运算符->->>运算符优先级混淆。铸造::结合比JSON(b)中运营商更强。

动态找出类型

这是您问题中更有趣的部分:

JSON文档中的年龄类型仍然是数字,所以PostgreSQL为什么不能自己弄清楚年龄呢?

SQL是一种严格类型化的语言,它不允许同一表达式integer在一行中求值text,而在下一行中求值。但是,由于您只对boolean测试结果感兴趣,因此可以使用CASE根据以下结果派生的表达式来解决此限制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;

>运算符右侧的无类型字符串文字会自动强制为左侧的值的相应类型。如果在其中放置类型化的值,则类型必须匹配或必须显式地对其进行强制转换-除非系统中已注册足够的隐式强制转换。

如果您知道所有数值实际上都是integer,则还可以:

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

上面的select语句比较的sqlalchemy核心表达式是什么?s = select([issues])。where(issues.c.id == mid).select_from(issues,..... externaljoin(issues.c.data ['type_id'] == mtypes.c.id) )...这里issue.c.data jsonb数据类型,正在与整数类型的
mtypes.c.id
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.