将 table 与 Postgres 中的数组进行比较

Compare table with array in Postgres

我需要将我的数组与 table 进行比较。

我需要知道数组中存在哪些代码而 table 中缺少哪些代码。 以及 table 中存在哪些代码而数组中缺少这些代码。

我正在使用 Node+KnexJS+PostgreSQL:

const myArray = `array['10001517','1509','1524','155400X','903B','910','1009201X']`
let divergence = await app.db.raw(`
    select file, t.code as acc_missing
    from unnest(${myArray}) file full join
        table_a as t 
        on t.code LIKE file
    where t.code is null or file is NULL
    AND t.version LIKE '010'
    AND t.inst = 300
`)

const errorDivergence = divergence.rows

我当前的查询执行此操作,但生成以下错误:

(node:26060) UnhandledPromiseRejectionWarning:
error: FULL JOIN is only supported with merge-joinable or hash-joinable join conditions

如错误消息所述,Postgres 仅支持 FULL [OUTER] JOIN 的连接条件,可用于合并连接或散列连接。 t.code LIKE file 不符合条件。

这是一个已知的限制。对于这种罕见的情况,人们还没有足够的兴趣来推动修复。参见:

但是,您的问题中没有任何内容表明您实际上需要 LIKE:

I need to know which codes exist in the array and are missing from the table. As well as which codes exist in the table and are missing from the array.

这表示相等 (=) - 效果很好:

SELECT file, t.code AS acc_missing
FROM   unnest('{10001517,1509,1524,155400X,903B,910,1009201X}'::text[]) file
FULL   join table_a t ON t.code = file    -- !
WHERE  t.code IS NULL
   OR  file IS NULL AND t.version LIKE '010' AND t.inst = 300;

您设置查询格式的方式表明您需要在 (t.code IS NULL OR file IS NULL) 周围加上括号。 ANDOR 之前绑定。 The manual about operator precedence.

OTOH,添加的谓词 AND t.version LIKE '010' AND t.inst = 300 只有在没有括号的情况下才有意义。因此,这是使用 LEFT & RIGHT JOIN:

实现原始查询的解决方法
SELECT file, t.code AS acc_missing
FROM   unnest('{10001517,1509,1524,155400X,903B,910,1009201X}'::text[]) file
LEFT   JOIN table_a t ON t.code LIKE file
WHERE  t.code IS NULL

UNION ALL
SELECT file, t.code AS acc_missing
FROM   unnest('{10001517,1509,1524,155400X,903B,910,1009201X}'::text[]) file
RIGHT  JOIN table_a t ON t.code LIKE file
WHERE  file IS NULL AND t.version LIKE '010' AND t.inst = 300;

或者:

SELECT file, t.code AS acc_missing
FROM   unnest('{10001517,1509,1524,155400X,903B,910,1009201X}'::text[]) file
LEFT   JOIN table_a t ON t.code LIKE file
WHERE  t.code IS NULL

UNION ALL
SELECT NULL, t.code
FROM   table_a t
WHERE (t.code LIKE ANY ('{10001517,1509,1524,155400X,903B,910,1009201X}'::text[])) IS NOT TRUE;

db<>fiddle here