sql >> Databáze >  >> RDS >> PostgreSQL

Jak porovnat prvky v poli složeného typu?

Funguje to:

SELECT *
FROM   element 
WHERE  (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
                           FROM   collection
                           WHERE  id = 1);

Nebo podrobnější, ale výhodnější :

SELECT *
FROM   element 
WHERE  (pk1, pk2, pk3) IN (SELECT (e).*
                           FROM   collection c, unnest(c.elements) e
                           WHERE  c.id = 1);

Robustnější a vyhýbá se vyhodnocování unnest() vícekrát. Viz:

Toto funguje také:

SELECT *
FROM   element 
WHERE  ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
                                FROM   collection
                                WHERE  id = 1);

Jádrem problému je, že IN provedení dílčího dotazu zná dvě samostatné formy. Citace příručky:

Váš dotaz, který selhal řeší na druhou formu, zatímco vy (pochopitelně) očekáváte první. Ale druhý formulář dělá toto:

Můj první a druhý dotaz aby to fungovalo rozložením typu řádku napravo od operátora. Postgres má tedy tři bigint hodnoty vlevo a vpravo a je spokojen.

Můj třetí dotaz zprovozní to vnořením typu řádku doleva do jiného konstruktor řádků . Postgres rozloží pouze první úroveň a skončí s jediným složeným typem – odpovídajícím jedinému složenému typu vpravo.

Všimněte si, že klíčové slovo ROW je vyžadováno pro jedno pole, které balíme. Příručka:

Váš pracovní dotaz se mírně liší, protože poskytuje seznam hodnot vpravo namísto poddotazu (set ). To je jiná implementace s jinou cestou kódu. Dokonce dostane samostatnou kapitolu v návodu . Tato varianta nemá žádnou speciální úpravu pro konstruktor ROW nalevo. Takže to prostě funguje podle očekávání (vámi).

Více ekvivalentních (pracovních) variant syntaxe s = 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[]);

Platí také s (pk1, pk2, pk3)::element_pk_t nebo ROW(pk1, pk2, pk3)::element_pk_t

Viz:

Protože váš zdroj je pole , Danielův druhý dotaz s (e.pk1, e.pk2, e.pk3) = ANY(c.elements) přirozeně se hodí.
Ale za sázku na nejrychlejší dotaz , moje peníze jsou na mé druhé variantě, protože očekávám, že bude optimálně využívat index PK.

Jen jako důkaz konceptu. Jak poznamenal a_horse:normalizovaný návrh DB bude pravděpodobně nejlépe škálovat.




  1. Je knihovna PDO rychlejší než nativní funkce MySQL?

  2. Android – Jak mohu předat data související se dvěma tabulkami metodě vkládání poskytovatele obsahu

  3. Go SQL driver get interface{} hodnoty sloupce

  4. mysql, iterujte názvy sloupců