Това работи:
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
FROM collection
WHERE id = 1);
Или по-многословен, нозапочитан :
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (e).*
FROM collection c, unnest(c.elements) e
WHERE c.id = 1);
По-стабилен и избягва оценяването на unnest()
много пъти. Вижте:
Това също работи:
SELECT *
FROM element
WHERE ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
FROM collection
WHERE id = 1);
Същността на проблема е, че IN
вземане на подзаявка познава две отделни форми. Цитирайки ръководството:
Вашата неуспешна заявка решава втората форма, докато вие (разбираемо) очаквате първата. Но втората форма прави това:
Моето първо и второ запитване накарайте го да работи чрез декомпозиране на типа ред
вдясно от оператора. Така Postgres има три bigint
стойности отляво и отдясно и е удовлетворено.
Моето трето запитване кара го да работи, като влага типа ред отляво в друг конструктор на ред . Postgres декомпозира само първото ниво и завършва с един съставен тип - съпоставяне на единичния съставен тип вдясно.
Обърнете внимание, че ключовата дума ROW
се изисква за едното поле, което обвиваме. Ръководството:
Вашата работеща заявка е леко различен, тъй като предоставя списък от стойности вдясно вместо подзаявка (комплект ). Това е различна реализация, която поема по различен кодов път. Дори получава отделна глава в ръководството . Този вариант няма специална обработка за ROW конструктор отляво. Така че работи според очакванията (от вас).
Още еквивалентни (работещи) варианти на синтаксис с = ANY
:
SELECT * FROM element
WHERE (pk1, pk2, pk3) = ANY ('{"(1,2,3)","(2,3,4)"}'::element_pk_t[]);
SELECT * FROM element
WHERE (pk1, pk2, pk3) = ANY (ARRAY[(1,2,3)::element_pk_t,(2,3,4)::element_pk_t]);
SELECT * FROM element
WHERE (pk1, pk2, pk3) = ANY (ARRAY[(1,2,3),(2,3,4)]::element[]);
Валидно и с (pk1, pk2, pk3)::element_pk_t
или ROW(pk1, pk2, pk3)::element_pk_t
Вижте:
Тъй като вашият източник е масив , втората заявка на Daniel с (e.pk1, e.pk2, e.pk3) = ANY(c.elements)
поддава се естествено.
Но за залог на най-бързото търсене , парите ми са за втория ми вариант, защото очаквам да използва оптимално PK индекса.
Просто като доказателство за концепцията. Както a_horse коментира:нормализиран дизайн на DB вероятно ще се мащабира най-добре.