sql >> Databasteknik >  >> RDS >> PostgreSQL

Posten som returneras från funktionen har kolumner sammanlänkade

I allmänhet för att dekomponera rader returneras från en funktion och få individuella kolumner:

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

När det gäller frågan:

Postgres 9.3 eller senare

Rengöringsmedel med 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 nyckelordet är implicit här, funktioner kan alltid referera till tidigare FROM föremål. Manualen:

LATERAL kan också föregå ett funktionsanrop FROM objekt, men i det här fallet är det ett brusord, eftersom funktionsuttrycket kan referera till tidigare FROM föremål i alla fall.

Relaterat:

  • Infoga flera rader i en tabell baserat på antalet i en annan tabell

Kort notation med kommatecken i FROM listan motsvarar (för det mesta) en CROSS JOIN LATERAL (samma som [INNER] JOIN LATERAL ... ON TRUE ) och tar därmed bort rader från resultatet där funktionsanropet inte returnerar någon rad. För att behålla sådana rader, använd LEFT JOIN LATERAL ... ON TRUE :

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

Använd inte heller NOT IN (subquery) när du kan undvika det. Det är det långsammaste och mest knepiga av flera sätt att göra det:

  • Välj rader som inte finns i andra tabeller

Jag föreslår att NOT EXISTS istället.

Postgres 9.2 eller äldre

Du kan anropa en set-returfunktion i SELECT list (som är en Postgres-förlängning av standard SQL). Av prestandaskäl görs detta bäst i en underfråga. Dekomponera den (välkända!) radtypen i den yttre frågan för att undvika upprepad utvärdering av funktionen:

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;

Relaterat svar av Craig Ringer med en förklaring, varför vi bättre bryts ner i den yttre frågan:

  • Hur undviker man flera funktionsevaler med syntaxen (func()).* i en SQL-fråga?

Postgres 10 tog bort konstigheter i beteendet hos set-returnerande funktioner i SELECT :

  • Vad är det förväntade beteendet för flera set-returfunktioner i SELECT-satsen?


  1. 2 sätt att returnera servernamnet i SQL Server (T-SQL)

  2. Hur man gör detta i Laravel, underfråga var i

  3. Problem med SQLiteOpenHelper på Android 2.X och 3.X

  4. Finns det en SQLite som motsvarar MySQL:s DESCRIBE [tabell]?