sql >> Database teknologi >  >> RDS >> PostgreSQL

Opdel funktionsreturneret post i flere kolonner

I Postgres 9.3 eller senere løses dette bedst med en LATERAL deltage:

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;

Undgår gentagen evaluering af funktionen (for hver kolonne i outputtet - funktionen skal kaldes for hver inputrække på begge måder).
LEFT JOIN LATERAL ... ON true for at undgå at tabe rækker fra venstre side, hvis funktionen ikke returnerer nogen række:

  • Hvad er forskellen mellem LATERAL og en underforespørgsel i PostgreSQL?

Opfølgning i din kommentar:

kun de udvidede kolonner produceret af funktionskaldet

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 da du er ligeglad med andre kolonner, kan du forenkle til:

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;

Hvilket er en implicit CROSS JOIN LATERAL . Hvis funktionen rent faktisk kan returnere "ingen række" lejlighedsvis, kan resultatet være anderledes:vi får ikke NULL-værdier for rækkerne, disse rækker er blot elimineret - og LIMIT tæller dem ikke mere.

I ældre versioner (eller generelt) kan du også bare dekomponere den sammensatte type med den rigtige syntaks:

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;

Ulempen er, at funktionen evalueres én gang for hver kolonne i funktionsoutputtet på grund af en svaghed i Postgres-forespørgselsplanlæggeren. Det er bedre at flytte opkaldet til en underforespørgsel eller CTE og dekomponere rækketypen i den ydre SELECT . Ligesom:

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 skal navngive individuelle kolonner og kan ikke slippe afsted med SELECT * medmindre du er ok med rækketypen i resultatet redundant.Relateret:

  • Undgå flere opkald på samme funktion, når du udvider sammensat resultat
  • Hvordan undgår man flere funktionsevaler med (func()).*-syntaksen i en SQL-forespørgsel?



  1. Markørbaserede poster i PostgreSQL

  2. Implementering af SQL Server Performance Indicator for forespørgsler, lagrede procedurer og triggere

  3. Sådan fortsætter du med STORE BLOB'er (>100MB) i Oracle ved hjælp af Hibernate

  4. Inkrementel datamaskering og kortlægning:Registrering af ændringer og opdatering...