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

Záznam vrácený z funkce má zřetězené sloupce

Obecně rozložení řádků vrácené z funkce a získat jednotlivé sloupce:

SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');

Pokud jde o dotaz:

Postgres 9.3 nebo novější

Čistič s JOIN LATERAL :

SELECT '2014-08-12' AS day, 0 AS inbytes, 0 AS outbytes
     , a.username, a.accountid, a.userid
     , f.*   -- but avoid duplicate column names!
FROM   account_tab a
     , account_servicetier_for_day(a.accountid, '2014-08-12') f  -- <-- HERE
WHERE  a.isdsl = 1
AND    a.dslservicetypeid IS NOT NULL
AND    NOT EXISTS (
   SELECT 1
   FROM   dailyaccounting_tab
   WHERE  day = '2014-08-12'
   AND    accountid = a.accountid
   )
ORDER  BY a.username;

LATERAL klíčové slovo je zde implicitní, funkce mohou vždy odkazovat dříve FROM položky. Manuál:

LATERAL může také předcházet volání funkce FROM item, ale v tomto případě se jedná o šumové slovo, protože výraz funkce může odkazovat na dřívější FROM položky v každém případě.

Související:

  • Vložit více řádků do jedné tabulky na základě čísla v jiné tabulce

Krátký zápis s čárkou v FROM seznam je (většinou) ekvivalentní CROSS JOIN LATERAL (stejné jako [INNER] JOIN LATERAL ... ON TRUE ) a tím odstraní řádky z výsledku, kde volání funkce nevrací žádný řádek. Chcete-li takové řádky zachovat, použijte LEFT JOIN LATERAL ... ON TRUE :

...
FROM  account_tab a
LEFT  JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...

Také nepoužívejte NOT IN (subquery) když se tomu můžete vyhnout. Je to nejpomalejší a nejsložitější z několika způsobů, jak toho dosáhnout:

  • Vyberte řádky, které se nenacházejí v jiné tabulce

Navrhuji NOT EXISTS místo toho.

Postgres 9.2 nebo starší

V SELECT můžete zavolat funkci vrácení sady seznam (což je Postgres rozšíření standardního SQL). Z důvodů výkonu se to nejlépe provádí v poddotazu. Rozložte (dobře známý!) typ řádku ve vnějším dotazu, abyste se vyhnuli opakovanému hodnocení funkce:

SELECT '2014-08-12' AS day, 0 AS inbytes, 0 AS outbytes
     , a.username, a.accountid, a.userid
     , (a.rec).*   -- but avoid duplicate column names!
FROM  (
   SELECT *, account_servicetier_for_day(a.accountid, '2014-08-12') AS rec
   FROM   account_tab a
   WHERE  a.isdsl = 1
   AND    a.dslservicetypeid Is Not Null
   AND    NOT EXISTS (
       SELECT 1
       FROM   dailyaccounting_tab
       WHERE  day = '2014-08-12'
       AND    accountid = a.accountid
      )
   ) a
ORDER  BY a.username;

Související odpověď Craiga Ringera s vysvětlením, proč je lepší rozložit ve vnějším dotazu:

  • Jak se vyhnout vícenásobným hodnotám funkcí pomocí syntaxe (func()).* v dotazu SQL?

Postgres 10 odstranil zvláštnosti v chování funkcí vracejících sadu v SELECT :

  • Jaké je očekávané chování pro více funkcí vracejících sadu v klauzuli SELECT?


  1. MariaDB CURRENT_TIMESTAMP() Vysvětleno

  2. Jak vytvořit parametrický dotaz v Accessu

  3. Nelze načíst DLL 'SqlServerSpatial.dll'

  4. MySQL a NoSQL:Pomozte mi vybrat ten správný