sql >> Database >  >> RDS >> PostgreSQL

Record geretourneerd door functie heeft kolommen aaneengeschakeld

Over het algemeen om rijen te ontleden geretourneerd van een functie en krijgt individuele kolommen:

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

Wat betreft de vraag:

Postgres 9.3 of nieuwer

Opschonen met 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;

De LATERAL trefwoord is hier impliciet, functies kunnen altijd eerder verwijzen FROM artikelen. De handleiding:

LATERAL kan ook voorafgaan aan een functieaanroep FROM item, maar in dit geval is het een ruiswoord, omdat de functie-uitdrukking kan verwijzen naar eerder FROM items in ieder geval.

Gerelateerd:

  • Voeg meerdere rijen in een tabel in op basis van het aantal in een andere tabel

Korte notatie met een komma in de FROM lijst is (meestal) gelijk aan een CROSS JOIN LATERAL (hetzelfde als [INNER] JOIN LATERAL ... ON TRUE ) en verwijdert dus rijen uit het resultaat waar de functieaanroep geen rij retourneert. Om dergelijke rijen te behouden, gebruikt u LEFT JOIN LATERAL ... ON TRUE :

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

Gebruik ook niet NOT IN (subquery) wanneer je het kunt vermijden. Het is de langzaamste en lastigste van de verschillende manieren om dat te doen:

  • Selecteer rijen die niet aanwezig zijn in een andere tabel

Ik stel voor NOT EXISTS in plaats daarvan.

Postgres 9.2 of ouder

U kunt een set-retourfunctie aanroepen in de SELECT list (wat een Postgres-extensie is van standaard SQL). Om prestatieredenen kan dit het beste in een subquery worden gedaan. Ontbind het (bekende!) rijtype in de buitenste query om herhaalde evaluatie van de functie te voorkomen:

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;

Gerelateerd antwoord van Craig Ringer met een uitleg, waarom we beter kunnen ontleden in de buitenste vraag:

  • Hoe vermijd je het evalueren van meerdere functies met de (func()).* syntaxis in een SQL-query?

Postgres 10 verwijderde eigenaardigheden in het gedrag van set-retourfuncties in de SELECT :

  • Wat is het verwachte gedrag voor functies die meerdere sets retourneren in de SELECT-component?


  1. Hoe specificeer je de IN-component in een dynamische query met behulp van een variabele?

  2. 3 manieren om een ​​waarde uit een JSON-document in SQLite te extraheren

  3. Dagen aftrekken van een datum in SQLite

  4. Hoe tijdgegevens uit een tekenreeks in SQL Server te extraheren of om te zetten?