Select 行嵌套 json 数组字段包含 PostgreSQL 中提供的数组中的任何值?
Select rows where nested json array field includes any of values from a provided array in PostgreSQL?
我正在尝试编写一个 sql 查询来查找 table 中与提供的 json 数组的任何值匹配的行。
更具体地说,我有以下数据库 table:
CREATE TABLE mytable (
name text,
id SERIAL PRIMARY KEY,
config json,
matching boolean
);
INSERT INTO "mytable"(
"name", "id", "config", "matching"
)
VALUES
(
E 'Name 1', 50,
E '{"employees":[1,7],"industries":["1","3","4","13","14","16"],"levels":["1110","1111","1112","1113","1114"],"revenue":[0,5],"states":["AK","Al","AR","AZ","CA","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL"]}',
TRUE
),
(
E 'Name 2', 63,
E '{"employees":[3,5],"industries":["1"],"levels":["1110"],"revenue":[2,5],"states":["AK","AZ","CA","CO","HI","ID","MT","NM","NV","OR","UT","WA","WY"]}',
TRUE,
),
(
E 'Name 3', 56,
E '{"employees":[0,0],"industries":["14"],"levels":["1111"],"revenue":[7,7],"states":["AK","AZ","CA","CO","HI","ID","MT","NM","NV","OR","UT","WA","WY"]}',
TRUE,
),
(
E 'Name 4', 61,
E '{"employees":[3,8],"industries":["1"],"levels":["1110"],"revenue":[0,5],"states":["AK","AZ","CA","CO","HI","ID","WA","WY"]}',
FALSE
);
我需要使用给定的过滤参数对此 table 执行搜索查询。过滤参数基本上对应于 config
字段中的 json 键。它们来自客户端,看起来像这样:
{"employees": [1, 8], "industries": ["12", "5"]}
{"states": ["LA", "WA", "CA"], "levels": ["1100", "1100"], "employees": [3]}
并且给定这样的过滤器,我需要在我的 table 中找到包含来自提供的每个过滤器键的相应过滤器键的任何数组元素的行。
因此,给定过滤器 {"employees": [1, 8], "industries": ["12", "5"]}
,查询必须 return 所有行,其中 config
字段中的 [employees
键包含 1
或8
AND 其中 config
字段中的 industries
键包含 12
或 5
);
我需要从 javascript 代码动态生成这样的查询,以便我可以 include/exclude 通过特定参数过滤 adding/removing AND
运算符。
到目前为止,我有一个超长的运行查询,它在config
字段中生成数组元素的所有可能组合,感觉很不对劲:
select * from mytable
cross join lateral json_array_elements(config->'employees') as e1
cross join lateral json_array_elements(config->'states') as e2
cross join lateral json_array_elements(config->'levels') as e3
cross join lateral json_array_elements(config->'revenue') as e4;
我也试过这样做:
select * from mytable
where
matching = TRUE
and (config->'employees')::jsonb @> ANY(ARRAY ['[1, 7, 8]']::jsonb[])
and (config->'states')::jsonb @> ANY(ARRAY ['["AK", "AZ"]']::jsonb[])
and ........;
然而这并没有奏效,尽管看起来很有希望。
此外,我尝试使用 ?|
运算符但无济于事。
基本上,我需要的是:在 json 字段中给定一个数组键,检查该字段是否包含另一个数组(这是我的过滤参数)中提供的任何值;我必须动态地为多个过滤参数执行此操作。
所以逻辑如下:
select all rows from the table
*where*
matching = TRUE
*and* config->key1 includes any of the keys from [5,6,8,7]
*and* config->key2 includes any of the keys from [8,6,2]
*and* so forth;
你能帮我实现这样一个 sql 查询吗?
或者这样的 sql 查询可能总是非常慢,最好在数据库级别之外进行此类过滤?
我会尝试类似的东西。我想有一定的副作用(例如,如果比较数据为空怎么办?)而且我没有在更大的数据集上测试它......这只是我想到的第一个......:[=14= ]
SELECT
*
FROM
mytable t
JOIN (SELECT '{"states": ["LA", "WA", "CA"], "levels": ["1100", "1100"], "employees": [3]}'::json as data) c
ON
CASE WHEN c.data -> 'employees' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'employees')) && ARRAY(SELECT json_array_elements_text(c.data -> 'employees'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'industries' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'industries')) && ARRAY(SELECT json_array_elements_text(c.data -> 'industries'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'states' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'states')) && ARRAY(SELECT json_array_elements_text(c.data -> 'states'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'revenue' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'revenue')) && ARRAY(SELECT json_array_elements_text(c.data -> 'revenue'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'levels' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'levels')) && ARRAY(SELECT json_array_elements_text(c.data -> 'levels'))
ELSE TRUE END
加入条件说明:
CASE WHEN c.data -> 'levels' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'levels')) && ARRAY(SELECT json_array_elements_text(c.data -> 'levels'))
ELSE TRUE END
如果您的比较数据不包含特定属性,则条件为 true
,因此将被忽略。如果它包含一个属性,通过将两个 JSON 数组转换为简单的 Postgres 数组
来比较此属性的 table 和比较数组
我正在尝试编写一个 sql 查询来查找 table 中与提供的 json 数组的任何值匹配的行。
更具体地说,我有以下数据库 table:
CREATE TABLE mytable (
name text,
id SERIAL PRIMARY KEY,
config json,
matching boolean
);
INSERT INTO "mytable"(
"name", "id", "config", "matching"
)
VALUES
(
E 'Name 1', 50,
E '{"employees":[1,7],"industries":["1","3","4","13","14","16"],"levels":["1110","1111","1112","1113","1114"],"revenue":[0,5],"states":["AK","Al","AR","AZ","CA","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL"]}',
TRUE
),
(
E 'Name 2', 63,
E '{"employees":[3,5],"industries":["1"],"levels":["1110"],"revenue":[2,5],"states":["AK","AZ","CA","CO","HI","ID","MT","NM","NV","OR","UT","WA","WY"]}',
TRUE,
),
(
E 'Name 3', 56,
E '{"employees":[0,0],"industries":["14"],"levels":["1111"],"revenue":[7,7],"states":["AK","AZ","CA","CO","HI","ID","MT","NM","NV","OR","UT","WA","WY"]}',
TRUE,
),
(
E 'Name 4', 61,
E '{"employees":[3,8],"industries":["1"],"levels":["1110"],"revenue":[0,5],"states":["AK","AZ","CA","CO","HI","ID","WA","WY"]}',
FALSE
);
我需要使用给定的过滤参数对此 table 执行搜索查询。过滤参数基本上对应于 config
字段中的 json 键。它们来自客户端,看起来像这样:
{"employees": [1, 8], "industries": ["12", "5"]}
{"states": ["LA", "WA", "CA"], "levels": ["1100", "1100"], "employees": [3]}
并且给定这样的过滤器,我需要在我的 table 中找到包含来自提供的每个过滤器键的相应过滤器键的任何数组元素的行。
因此,给定过滤器 {"employees": [1, 8], "industries": ["12", "5"]}
,查询必须 return 所有行,其中 config
字段中的 [employees
键包含 1
或8
AND 其中 config
字段中的 industries
键包含 12
或 5
);
我需要从 javascript 代码动态生成这样的查询,以便我可以 include/exclude 通过特定参数过滤 adding/removing AND
运算符。
到目前为止,我有一个超长的运行查询,它在config
字段中生成数组元素的所有可能组合,感觉很不对劲:
select * from mytable
cross join lateral json_array_elements(config->'employees') as e1
cross join lateral json_array_elements(config->'states') as e2
cross join lateral json_array_elements(config->'levels') as e3
cross join lateral json_array_elements(config->'revenue') as e4;
我也试过这样做:
select * from mytable
where
matching = TRUE
and (config->'employees')::jsonb @> ANY(ARRAY ['[1, 7, 8]']::jsonb[])
and (config->'states')::jsonb @> ANY(ARRAY ['["AK", "AZ"]']::jsonb[])
and ........;
然而这并没有奏效,尽管看起来很有希望。
此外,我尝试使用 ?|
运算符但无济于事。
基本上,我需要的是:在 json 字段中给定一个数组键,检查该字段是否包含另一个数组(这是我的过滤参数)中提供的任何值;我必须动态地为多个过滤参数执行此操作。
所以逻辑如下:
select all rows from the table
*where*
matching = TRUE
*and* config->key1 includes any of the keys from [5,6,8,7]
*and* config->key2 includes any of the keys from [8,6,2]
*and* so forth;
你能帮我实现这样一个 sql 查询吗?
或者这样的 sql 查询可能总是非常慢,最好在数据库级别之外进行此类过滤?
我会尝试类似的东西。我想有一定的副作用(例如,如果比较数据为空怎么办?)而且我没有在更大的数据集上测试它......这只是我想到的第一个......:[=14= ]
SELECT
*
FROM
mytable t
JOIN (SELECT '{"states": ["LA", "WA", "CA"], "levels": ["1100", "1100"], "employees": [3]}'::json as data) c
ON
CASE WHEN c.data -> 'employees' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'employees')) && ARRAY(SELECT json_array_elements_text(c.data -> 'employees'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'industries' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'industries')) && ARRAY(SELECT json_array_elements_text(c.data -> 'industries'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'states' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'states')) && ARRAY(SELECT json_array_elements_text(c.data -> 'states'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'revenue' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'revenue')) && ARRAY(SELECT json_array_elements_text(c.data -> 'revenue'))
ELSE TRUE END
AND
CASE WHEN c.data -> 'levels' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'levels')) && ARRAY(SELECT json_array_elements_text(c.data -> 'levels'))
ELSE TRUE END
加入条件说明:
CASE WHEN c.data -> 'levels' IS NOT NULL THEN
ARRAY(SELECT json_array_elements_text(t.config -> 'levels')) && ARRAY(SELECT json_array_elements_text(c.data -> 'levels'))
ELSE TRUE END
如果您的比较数据不包含特定属性,则条件为 true
,因此将被忽略。如果它包含一个属性,通过将两个 JSON 数组转换为简单的 Postgres 数组