Можно найти запись, которая соответствует любому кортежу из списка, например:

SELECT * FROM tags
WHERE (tags.namespace, tags.name) IN (('genre', 'Action'), ('content', 'Violence'));

Но можно ли найти запись, которая соответствует всем кортежам из списка?

Согласно документации Postgres, это похоже на работу для = ALL:

Результатом ALL является "истина", если все сравнения дают истинное значение (включая случай, когда в массиве нулевые элементы). Результат будет «ложным», если будет обнаружен какой-либо ложный результат.

Но, как ни странно, этот оператор не совместим со списком значений кортежа. Я пробовал следующее:

SELECT * FROM tags
WHERE (tags.namespace, tags.name) = ALL (('genre', 'Action'), ('content', 'Violence'));

... что дает мне синтаксическую ошибку в первой запятой.

Я также пробовал:

SELECT * FROM tags
WHERE (tags.namespace, tags.name) = ALL (ARRAY[('genre', 'Action'), ('content', 'Violence')]);

... что дает мне прекрасный cannot compare dissimilar column types namespace and unknown at record column 1.

В идеале я хотел бы сохранить решение в формате списка значений.

Вот схема таблицы tags:

CREATE TYPE namespace AS ENUM ('genre', 'type', 'content', 'any');

CREATE TABLE tags (
    comic UUID NOT NULL REFERENCES comics ON DELETE CASCADE,
    namespace namespace NOT NULL,
    name VARCHAR NOT NULL,
    PRIMARY KEY(comic, namespace, name)
);
0
mbStavola 21 Июн 2020 в 02:43

1 ответ

Лучший ответ

Используйте агрегацию:

SELECT t.comic
FROM tags t
WHERE (t.namespace, t.name) IN (('genre', 'Action'), ('content', 'Violence'))
GROUP BY t.comic
HAVING COUNT(*) = 2;  -- 2 is the size of the list

«2» - это количество совпадающих тегов - эта версия предполагает (разумно), что теги не являются дубликатами для данного comic.

Если вы храните значения в массиве, вы можете использовать конструкцию массива в WHERE и размер массива в HAVING.

1
Gordon Linoff 20 Июн 2020 в 23:45