从 Postgres 中的子查询构造值的 ARRAY 并将其用于 WHERE 子句

Construct ARRAY of values from a subquery in Postgres and use it in a WHERE clause

这些是我拥有的两个表的示例:

Table 1

  material_id (int)        codes (jsonb)        
---------------------    -------------------------------      
        1                  ['A-12','B-19','A-14','X-22']           
        2                  ['X-106','A-12','X-22','B-19']        
        .
        .

Table 2

   user_id        material_list (jsonb)
 -----------    --------------------
     1                 [2,3]
     2                 [1,2]
     .
     .

Table 1 包含 material 个 ID 和与之关联的一组代码 material。

Table 2 包含用户 ID。每个用户都有一个与之关联的 material 列表,并将其保存在一个 material ID

数组中

我想获取所有 material 具有特定代码的用户 ID 列表。这是我试过的查询,但它引发了语法错误:

SELECT user_id from table2
WHERE material_list ?| array(SELECT material_id 
                             FROM table1 where codes ?| ['A-12','B-19]);

我不知道如何修复它。

这似乎是取消嵌套 json 数组的过程:

select t2.user_id
from table2 t2
where exists (select 1
              from table1 t1  join 
                   jsonb_array_elements_text(t2.material_list) j(material_id)
                   on t1.material_id = j.material_id::int join
                   jsonb_array_elements_text(t1.codes) j2(code)
                   on j2.code in ('A-12', 'B-19')
             );

Here 是一个 db<>fiddle.

您的查询因多种原因而失败。

首先,['A-12','B-19] 不是有效的 Postgres 文本数组。使用数组常量或数组构造函数:

'{A-12,B-19}'
ARRAY['A-12','B-19']

参见:

  • How to pass custom type array to Postgres function
  • Pass array literal to PostgreSQL function

接下来,运算符 ?| 要求 text[] 向右,而您提供 int[].

最后,无论如何它都行不通,因为运算符 ?| 检查 JSON strings,而不是 numbersThe manual:

Do any of the strings in the text array exist as top-level keys or array elements?

将 JSON 数组转换为 Postgres 整数数组,然后使用 array overlap operator &&

SELECT user_id
FROM   tbl2
WHERE  ARRAY(SELECT jsonb_array_elements_text(material_list)::int)
    && ARRAY(SELECT material_id FROM tbl1 where codes ?| array['A-12','B-19']);

我强烈建议更改您的 table 以将 material_list 中的 JSON 数组永久转换为 Postgres 整数数组 (int[])。参见:

然后查询变得更简单:

SELECT user_id
FROM   tbl2
WHERE  material_list && ARRAY(SELECT material_id FROM tbl1 where codes ?| '{A-12,B-19}');

db<>fiddle here

或者 - 我敢说吗? - 正确地正常化你的关系设计。参见:

  • How to implement a many-to-many relationship in PostgreSQL?