sql >> Databasteknik >  >> RDS >> PostgreSQL

Dela upp funktionsreturnerad post i flera kolumner

I Postgres 9.3 eller senare löses detta bäst med en LATERAL gå med:

SELECT *
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

Undviker upprepad utvärdering av funktionen (för varje kolumn i utgången - funktionen måste anropas för varje inmatningsrad i båda riktningarna).
LEFT JOIN LATERAL ... ON true för att undvika att rader släpps från vänster sida om funktionen inte returnerar någon rad:

  • Vad är skillnaden mellan LATERAL och en underfråga i PostgreSQL?

Uppföljning i din kommentar:

endast de utökade kolumner som skapas av funktionsanropet

SELECT x.*  -- that's all!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

Men eftersom du inte bryr dig om andra kolumner kan du förenkla till:

SELECT x.*
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
     , hi_lo(a.actor_id, length(a.name), ma.movie_id) x
LIMIT  10;

Vilket är en implicit CROSS JOIN LATERAL . Om funktionen faktiskt kan returnera "ingen rad" ibland, kan resultatet bli annorlunda:vi får inga NULL-värden för raderna, dessa rader är bara eliminerade - och LIMIT räknar dem inte längre.

I äldre versioner (eller generellt) kan du också bara dekomponera den sammansatta typen med rätt syntax:

SELECT *, (hi_lo(a.actor_id, length(a.name), ma.movie_id)).*  -- note extra parentheses!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LIMIT  10;

Nackdelen är att funktionen utvärderas en gång för varje kolumn i funktionsutgången på grund av en svaghet i Postgres frågeplanerare. Det är bättre att flytta anropet till en underfråga eller CTE och dekomponera radtypen i den yttre SELECT . Gilla:

SELECT actor_id, movie_id, (x).*  -- explicit column names for the rest
FROM  (
   SELECT *, hi_lo(a.actor_id, length(a.name), ma.movie_id) AS x
   FROM   actors a 
   JOIN   movies_actors ma on a.actor_id = ma.movie_id 
   LIMIT  10
   ) sub;

Men du måste namnge enskilda kolumner och kan inte komma undan med SELECT * om du inte är ok med radtypen i resultatet redundant.Relaterat:

  • Undvik flera anrop på samma funktion när du utökar sammansatta resultat
  • Hur undviker man flera funktionsevaler med syntaxen (func()).* i en SQL-fråga?



  1. MySQL REGEXP-exempel

  2. använd en variabel för tabellnamn i mysql sproc

  3. Ändra en MySQL-kolumn till AUTO_INCREMENT

  4. Konvertera 'datetimeoffset' till 'time' i SQL Server (T-SQL-exempel)