PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да съпоставим елементи в масив от съставен тип?

Това работи:

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 вероятно ще се мащабира най-добре.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как работи функцията Radians() в PostgreSQL

  2. Как мога да върна '0' от заявка в pgsql, ако редът не съществува?

  3. Postgres DB Trigger, извикващ Java функция

  4. Има ли безопасен начин за модифициране на таблицата pg_constraint, така че да не се извършва повече проверка (временно)?

  5. GORM създава запис, който може вече да съществува