簡體   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