存在于 JSON 字段检查查询
Existance in JSON field check query
我在我的数据库中使用 PostgreSQL JSON 类型字段。
JSON格式:
[
{"id": "13", "something": "not_important"},
{"id": "5426565165191919", "something": "not_important"},
{"id": "46", "something": "not_important"}
...
]
ID 列表,例如 ["13", "46", "84"]
。
如何进行查询,告诉我某些 ID 不存在? (哪一个不重要。)
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
查询)只是替代实际的 table t
。
- 使用
LEFT JOIN / NOT NULL
识别缺失值。细节:
- Select rows which are not present in other table
- 假设
bigint
足够宽以容纳您的 id
值。否则,切换到 numeric
.
此相关答案中的更多解释:
- Query for array elements inside JSON type
您可以通过将 "expected" ID 与 "actual" ID 左连接,然后在结果集中过滤 "actual" ID [=59] 的行来完成此操作=] 加入失败。唯一的技巧是从 JSON 中提取整数 id 值。假设您在 SQL:
中对 all id 进行硬编码,这就是它可以完成的方式
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
文本直接转换为整数值,例如 int
或 bigint
,即使整个 json
文本仅包含有效的 int
/bigint
,但您可以通过 varchar
到达那里:
select '34'::json::bigint; -- "ERROR: cannot cast type json to bigint"
select '34'::json::varchar::bigint; -- works, 34
这就是为什么我必须将 json
值转换为 ::varchar::bigint
。
此外,我不得不使用 substring()
从他们的双引号字符串中提取预期的 ID,否则 ::bigint
转换将不起作用。
此外,次要的一点是,我使用了 bigint
而不是 int
,因为那里的数字相当大 (5426565165191919)。
如果您只想 select 一个布尔值,指示是否至少缺少一个预期 ID,您可以将 select 子句更改为:
select
case when count(expected.id)>0 then true else false end some_missing
我在我的数据库中使用 PostgreSQL JSON 类型字段。
JSON格式:
[
{"id": "13", "something": "not_important"},
{"id": "5426565165191919", "something": "not_important"},
{"id": "46", "something": "not_important"}
...
]
ID 列表,例如 ["13", "46", "84"]
。
如何进行查询,告诉我某些 ID 不存在? (哪一个不重要。)
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
查询)只是替代实际的 tablet
。 - 使用
LEFT JOIN / NOT NULL
识别缺失值。细节:- Select rows which are not present in other table
- 假设
bigint
足够宽以容纳您的id
值。否则,切换到numeric
.
此相关答案中的更多解释:
- Query for array elements inside JSON type
您可以通过将 "expected" ID 与 "actual" ID 左连接,然后在结果集中过滤 "actual" ID [=59] 的行来完成此操作=] 加入失败。唯一的技巧是从 JSON 中提取整数 id 值。假设您在 SQL:
中对 all id 进行硬编码,这就是它可以完成的方式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
文本直接转换为整数值,例如 int
或 bigint
,即使整个 json
文本仅包含有效的 int
/bigint
,但您可以通过 varchar
到达那里:
select '34'::json::bigint; -- "ERROR: cannot cast type json to bigint"
select '34'::json::varchar::bigint; -- works, 34
这就是为什么我必须将 json
值转换为 ::varchar::bigint
。
此外,我不得不使用 substring()
从他们的双引号字符串中提取预期的 ID,否则 ::bigint
转换将不起作用。
此外,次要的一点是,我使用了 bigint
而不是 int
,因为那里的数字相当大 (5426565165191919)。
如果您只想 select 一个布尔值,指示是否至少缺少一个预期 ID,您可以将 select 子句更改为:
select
case when count(expected.id)>0 then true else false end some_missing