Сравните таблицу с массивом в Postgres - PullRequest
0 голосов
/ 06 марта 2020

Мне нужно сравнить мой массив с таблицей.

Мне нужно знать, какие коды существуют в массиве и отсутствуют в таблице. А также какие коды существуют в таблице и отсутствуют в массиве.

Я использую 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

1 Ответ

1 голос
/ 06 марта 2020

Как говорится в сообщении об ошибке, Postgres поддерживает только условия соединения для FULL [OUTER] JOIN, которые можно использовать при объединении слиянием или при sh -соединении. t.code LIKE file не подходит для этого.

Это известное ограничение. Просто не было достаточно интереса для редкого случая, чтобы мотивировать исправление. См .:

Однако в ваших вопросах ничего не говорится о том, что вам действительно нужно LIKE:

Мне нужно знать, какие коды существуют в массиве и отсутствуют в таблице. А также какие коды существуют в таблице и отсутствуют в массиве.

Это указывало бы на равенство (=) - что отлично работает:

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). AND связывается до OR. Руководство по приоритету оператора .

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 здесь

...