Gol*_*den 23 postgresql cast json operator postgresql-9.5
我有一个表,persons它包含两列,一个id和一个基于 JSONB 的data列(这个表只是为了演示目的而制作的,以使用 PostgreSQL 的 JSON 支持)。
现在,假设它包含两条记录:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Run Code Online (Sandbox Code Playgroud)
现在,假设我想得到每个 25 岁以上的人的名字。我尝试过的是:
select data->'name' as name from persons where data->'age' > 25
Run Code Online (Sandbox Code Playgroud)
不幸的是,这会导致错误。我可以通过使用->>代替来解决它->,但是比较不再按预期工作,因为不是比较数字,而是比较它们作为字符串的表示:
select data->'name' as name from persons where data->>'age' > '25'
Run Code Online (Sandbox Code Playgroud)
然后我发现我实际上可以通过使用->和强制转换来解决这个问题int:
select data->'name' as name from persons where cast(data->'age' as int) > 25
Run Code Online (Sandbox Code Playgroud)
这有效,但我必须知道实际类型并不是那么好(ageJSON 文档中的类型是number无论如何,那么为什么 PostgreSQL 不能自己弄清楚呢?)。
然后我发现如果我手动转换为text使用::语法,一切都按预期工作 - 尽管我们现在再次比较字符串。
select data->'name' as name from persons where data->'age'::text > '25'
Run Code Online (Sandbox Code Playgroud)
如果我然后用名字而不是年龄来尝试这个,它不起作用:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Run Code Online (Sandbox Code Playgroud)
这会导致错误:
类型 json 的无效输入语法
很明显,我在这里没有得到任何东西。不幸的是,很难找到在 PostgreSQL 中使用 JSON 的任何实际示例。
任何提示?
Erw*_*ter 22
这不起作用,因为它试图将jsonb值转换为integer.
select data->'name' as name from persons where cast(data->'age' as int) > 25Run Code Online (Sandbox Code Playgroud)
这实际上会起作用:
SELECT data->'name' AS name FROM persons WHERE cast(data->>'age' AS int) > 25;Run Code Online (Sandbox Code Playgroud)
或更短:
SELECT data->'name' AS name FROM persons WHERE (data->>'age')::int > 25;
Run Code Online (Sandbox Code Playgroud)
和这个:
SELECT data->'name' AS name FROM persons WHERE data->>'name' > 'Jenny';
Run Code Online (Sandbox Code Playgroud)
似乎与两个运算符->和->>和运算符优先级混淆。演员::绑定比 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;
Run Code Online (Sandbox Code Playgroud)
>运算符右侧的无类型字符串文字会自动强制为左侧值的相应类型。如果您将类型化值放在那里,则该类型必须匹配,或者您必须显式转换它 - 除非在系统中注册了足够的隐式转换。
如果您知道所有数值实际上都是integer,您还可以:
... (data->>'age')::int > 25 ...
Run Code Online (Sandbox Code Playgroud)