Postgresql:通过 json 对象数组中的文本查找行
Postgresql: Find row via text in json array of objects
我试图在我的 Postgresql 数据库中查找 json 列包含给定文本的行。
行架构:
id | name | subitems
-----------------------------------------------------------------
1 | "item 1" | [{name: 'Subitem A'}, {name: 'Subitem B'}]
2 | "item 2" | [{name: 'Subitem C'}, {name: 'Subitem D'}]
我想要的查询结果 'Subitem B'
id | name | subitems
-----------------------------------------------------------------
1 | "item 1" | [{name: 'Subitem A'}, {name: 'Subitem B'}]
我可以这样搜索第一个子项:
WHERE lower(subitems->0->>\'name\') LIKE '%subitem a%'
但显然我找不到任何其他子项目,但第一个这样。
我可以得到我所有子项的名称:
SELECT lower(json_array_elements(subitems)->>'name') FROM ...
但它给了我 2 行包含名称:
lower
----------------------------------------------------------------
"subitem a"
"subitem b"
我实际需要的是包含该项目的 1 行。
谁能告诉我怎么做?
你快到了。您的查询:
SELECT lower(json_array_elements(subitems)->>'name') FROM foo;
这将为您提供要过滤的内容。如果将其放入子查询中,您将获得所需的结果:
# SELECT *
FROM foo f1
WHERE 'subitem a' IN
(SELECT lower(json_array_elements(subitems)->>'name')
FROM foo f2 WHERE f1.id = f2.id
);
id | name | subitems
----+--------+------------------------------------------------
1 | item 1 | [{"name": "Subitem A"}, {"name": "Subitem B"}]
(1 row)
编辑添加
好的,要支持 LIKE 式匹配,您必须更深入一点,将子查询放入您的子查询中。由于这有点难读,我改用 common table expressions.
WITH all_subitems AS (
SELECT id, json_array_elements(subitems)->>'name' AS subitem
FROM foo),
matching_items AS (
SELECT id
FROM all_subitems
WHERE
lower(subitem) LIKE '%subitem a%')
SELECT *
FROM foo
WHERE
id IN (SELECT id from matching_items);
这应该可以满足您的需求。请注意,我将对 lower
的调用上移了一个级别,因此它与 LIKE
并排。这意味着过滤条件在一个地方,因此您可以更轻松地切换到正则表达式匹配或其他任何方式。
我试图在我的 Postgresql 数据库中查找 json 列包含给定文本的行。
行架构:
id | name | subitems
-----------------------------------------------------------------
1 | "item 1" | [{name: 'Subitem A'}, {name: 'Subitem B'}]
2 | "item 2" | [{name: 'Subitem C'}, {name: 'Subitem D'}]
我想要的查询结果 'Subitem B'
id | name | subitems
-----------------------------------------------------------------
1 | "item 1" | [{name: 'Subitem A'}, {name: 'Subitem B'}]
我可以这样搜索第一个子项:
WHERE lower(subitems->0->>\'name\') LIKE '%subitem a%'
但显然我找不到任何其他子项目,但第一个这样。
我可以得到我所有子项的名称:
SELECT lower(json_array_elements(subitems)->>'name') FROM ...
但它给了我 2 行包含名称:
lower
----------------------------------------------------------------
"subitem a"
"subitem b"
我实际需要的是包含该项目的 1 行。
谁能告诉我怎么做?
你快到了。您的查询:
SELECT lower(json_array_elements(subitems)->>'name') FROM foo;
这将为您提供要过滤的内容。如果将其放入子查询中,您将获得所需的结果:
# SELECT *
FROM foo f1
WHERE 'subitem a' IN
(SELECT lower(json_array_elements(subitems)->>'name')
FROM foo f2 WHERE f1.id = f2.id
);
id | name | subitems
----+--------+------------------------------------------------
1 | item 1 | [{"name": "Subitem A"}, {"name": "Subitem B"}]
(1 row)
编辑添加
好的,要支持 LIKE 式匹配,您必须更深入一点,将子查询放入您的子查询中。由于这有点难读,我改用 common table expressions.
WITH all_subitems AS (
SELECT id, json_array_elements(subitems)->>'name' AS subitem
FROM foo),
matching_items AS (
SELECT id
FROM all_subitems
WHERE
lower(subitem) LIKE '%subitem a%')
SELECT *
FROM foo
WHERE
id IN (SELECT id from matching_items);
这应该可以满足您的需求。请注意,我将对 lower
的调用上移了一个级别,因此它与 LIKE
并排。这意味着过滤条件在一个地方,因此您可以更轻松地切换到正则表达式匹配或其他任何方式。