2015-01-31 62 views
0

我正在使用PostgreSQL JSON类型字段在我的数据库中。存在JSON字段检查查询

JSON格式:

[ 
    {"id": "13", "something": "not_important"}, 
    {"id": "5426565165191919", "something": "not_important"}, 
    {"id": "46", "something": "not_important"} 
    ... 
] 

["13", "46", "84"] ID列表。

如何使查询告诉我一些ID不存在? (不重要其中之一。)

回答

2
WITH t(data) AS (
    VALUES ('   [ 
    {"id": "13", "something": "not_important"}, 
    {"id": "5426565165191919", "something": "not_important"}, 
    {"id": "46", "something": "not_important"} 
    ]'::json) 
    ) 
SELECT NOT EXISTS (
    SELECT data::text, o::text -- cast to text for display in fiddle 
    FROM t, json_array_elements(t.data) AS d(o) 
    RIGHT JOIN unnest('{13,46,84}'::bigint[]) u(id) ON u.id = (d.o->>'id')::bigint 
    WHERE d.o IS NULL 
    ) AS all_found; 
  • 的CTE(WITH查询)只是替代了实际的表t
  • 使用LEFT JOIN/NOT NULL来识别缺失值。详细信息:
  • 假设bigint足够宽,握住你的id值。否则,切换到numeric。在这个相关答案

SQL Fiddle.

更多的解释:

+0

它的作品!谢谢。 – 2015-01-31 19:32:24

0

您可以通过左加入您的 “预期” IDS对 “实际的” IDS做到这一点,然后过滤“实际”ids表未能加入的结果集中的行。唯一的诀窍是从JSON中提取完整的id值。这是它如何做,假设你是被硬编码所有 IDS就在SQL:

select 
    expected.id 
from 
    (select substring(value::varchar from 2 for char_length(value::varchar)-2)::bigint id from json_array_elements('["13","46","84"]'::json)) expected 
    left join (select (value->>'id')::bigint id from json_array_elements('[{"id":"13"},{"id":"5426565165191919"},{"id":"46"}]'::json)) actual on actual.id=expected.id 
where 
    actual.id is null 
; 

在上面的查询,我打电话json_array_elements()来提取每个JSON字符串的单独的数组元素。由于目标JSON字符串具有对象数组元素,因此我们必须进一步提取"id"值,这可以使用->运算符完成。请注意,value似乎是由json_array_elements()函数分配给单列输出的默认名称。

一个怪癖的是,所提取的JSON(即value值)仍json型的,似乎不能直接投json文字的整数值,例如intbigint,即使整个json文本仅包含一个有效的int/bigint,但你可以通过varchar到那里:

select '34'::json::bigint; -- "ERROR: cannot cast type json to bigint" 
select '34'::json::varchar::bigint; -- works, 34 

这就是为什么我不得不与::varchar::bigintjson值。

此外,我不得不使用substring()从他们的双引号字符串中提取预期的id,因为::bigint转换将不起作用。

此外,小点,我用bigint而不是int,因为你有一个相当大的数字(5426565165191919)。

如果你只想选择一个布尔值,表示如果至少有一个预期的ID丢失,您可以更改在SELECT子句为:

select 
    case when count(expected.id)>0 then true else false end some_missing 
+1

您可以使用[' - >>'](http://www.postgresql.org/docs/current/interactive/functions-json.html)(它返回'text')而不是' - >'。 – 2015-01-31 18:53:08

+0

啊,好点。有没有办法避免预期的id子查询中的额外转换?这里没有取消引用,它只是'value :: varchar',所以你不能使用' - >>'。 – bgoldst 2015-01-31 18:55:26

+0

只要您提供输入为JSON数组,您就可以使用'json_array_elements()'的另一个实例。我在我的答案中使用了一个普通数组('bigint []')和相应的'unnest()'。 – 2015-01-31 18:59:27