PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Der von der Funktion zurückgegebene Datensatz hat verkettete Spalten

Im Allgemeinen um Zeilen zu zerlegen von einer Funktion zurückgegeben und einzelne Spalten erhalten:

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

Was die Abfrage angeht:

Postgres 9.3 oder neuer

Reiniger mit 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;

Der LATERAL Schlüsselwort ist hier implizit, Funktionen können sich immer auf früheres FROM beziehen Produkte. Das Handbuch:

LATERAL kann auch vor einem Funktionsaufruf FROM stehen item, aber in diesem Fall handelt es sich um ein Füllwort, da der Funktionsausdruck auf frühere FROM verweisen kann Artikel auf jeden Fall.

Verwandte:

  • Einfügen mehrerer Zeilen in eine Tabelle basierend auf Zahlen in einer anderen Tabelle

Kurzschreibweise mit Komma im FROM list ist (meistens) äquivalent zu einem CROSS JOIN LATERAL (dasselbe wie [INNER] JOIN LATERAL ... ON TRUE ) und entfernt somit Zeilen aus dem Ergebnis, wo der Funktionsaufruf keine Zeile zurückgibt. Um solche Zeilen beizubehalten, verwenden Sie LEFT JOIN LATERAL ... ON TRUE :

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

Verwenden Sie außerdem nicht NOT IN (subquery) wenn Sie es vermeiden können. Dies ist die langsamste und kniffligste von mehreren Möglichkeiten, dies zu tun:

  • Wählen Sie Zeilen aus, die in keiner anderen Tabelle vorhanden sind

Ich empfehle NOT EXISTS stattdessen.

Postgres 9.2 oder älter

Sie können im SELECT eine set-returning-Funktion aufrufen list (eine Postgres-Erweiterung von Standard-SQL). Dies geschieht aus Performance-Gründen am besten in einer Unterabfrage. Zerlegen Sie den (bekannten!) Zeilentyp in der äußeren Abfrage, um eine wiederholte Auswertung der Funktion zu vermeiden:

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;

Verwandte Antwort von Craig Ringer mit einer Erklärung, warum wir besser in der äußeren Abfrage zerlegen:

  • Wie kann man mehrere Funktionsauswertungen mit der (func()).*-Syntax in einer SQL-Abfrage vermeiden?

Postgres 10 Kuriositäten im Verhalten von Set-zurückgebenden Funktionen in SELECT entfernt :

  • Was ist das erwartete Verhalten für mehrere Set-zurückgebende Funktionen in der SELECT-Klausel?