繁体   English   中英

Select 行,其中嵌套的 json 数组字段包括 PostgreSQL 中提供的数组中的任何值?

[英]Select rows where nested json array field includes any of values from a provided array in PostgreSQL?

我正在尝试编写一个 sql 查询,该查询将在表中找到与提供的 json 数组的任何值匹配的行。

更具体地说,我有以下数据库表:

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
  );

我需要使用给定的过滤参数对此表执行搜索查询。 过滤参数基本对应config字段中的 json 键。 它们来自客户端,看起来像这样:

{"employees": [1, 8], "industries": ["12", "5"]}
{"states": ["LA", "WA", "CA"], "levels": ["1100", "1100"], "employees": [3]}

并且给定这样的过滤器,我需要在我的表中找到包含来自提供的每个过滤器键的相应过滤器键的任何数组元素的行。

所以给定过滤器{"employees": [1, 8], "industries": ["12", "5"]}查询必须返回所有行,其中( config字段中的employees键包含18并且config字段中的industries键包含125 );

我需要从 javascript 代码动态生成这样的查询,以便我可以通过添加/删除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 查询总是非常慢,最好在数据库级别之外进行这种过滤?

我会尝试类似的东西。 我想有一定的副作用(例如,如果比较数据为空怎么办?)而且我没有在更大的数据集上测试它......这只是我想到的第一个......:

演示:db<>小提琴

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 ,因此将被忽略。 If it contains an attribute, compare the table and comparision arrays for this attribute by transforming both JSON arrays into simple Postgres arrays

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM