Comprensione di Set Returning Function (SRF) nell'elenco SELECT


8

Perché esiste una differenza nel comportamento tra l'utilizzo di una funzione di ritorno (SRF) nell'elenco SELECT e l'utilizzo di SRF nella clausola FROM?

Ad esempio, per un semplice SRF che restituisce 2 righe:

CREATE OR REPLACE FUNCTION gen_series(out integer, out int)
  RETURNS SETOF record AS $$
  SELECT 1,1
  UNION
  SELECT 2,2;
$$ LANGUAGE SQL;

SELECT gen_series(); restituisce due righe a colonna singola contenenti ciascuna un record:

=>  gen_series 
------------
 (1,1)
 (2,2)
(2 rows)

Considerando che SELECT * FROM gen_series();restituisce due righe con il record espanso:

=>  column1 | column2 
---------+---------
       1 |       1
       2 |       2
(2 rows)

In confronto, se l'SRF restituisce una singola colonna, la chiamata all'SRF nella clausola SELECT o FROM non fa alcuna differenza. per esempio:

=> SELECT generate_series(1,2);
 generate_series 
-----------------
               1
               2
(2 rows)

=> SELECT * FROM generate_series(1,2);
 generate_series 
-----------------
               1
               2
(2 rows)

Le mie domande sono:

  1. Non capisco bene perché nel secondo caso, il comportamento SRF sia diverso dal primo caso solo perché la tabella restituita ha una singola colonna. Questo comportamento è davvero coerente in termini di tipi, tuple e set?

  2. Qual è la differenza tra i due casi che porta al diverso comportamento?

  3. L'SRF può essere utilizzato come tabelle come mostrato sopra, ma le tabelle possono essere utilizzate anche per sostituire gli SRF? per esempio

    SELECT my_table; 

Apparentemente, questo non può essere fatto, ma perché è SELECT my_SRF();possibile, mentre SELECT my_table;non è permesso (in termini di relazioni e matematica)?


SELECT my_table;non è una sintassi valida
Mladen Uzelac,

Risposte:


3

Postgres tratta il caso semplice in modo diverso. Le colonne multiple vengono trattate come tipo composito (riga della tabella), che viene decomposto solo con SELECT * FROM ..., mentre una singola colonna di tipo scalare viene trattata come tale, senza wrapper di tipo composito aggiunto. Quindi SELECT my_SRF()produce lo stesso SELECT * FROM my_SRF()del caso semplice. Il manuale sulle funzioni della tabella :

Le funzioni di tabella sono funzioni che producono un insieme di righe, costituite da tipi di dati di base (tipi scalari) o tipi di dati compositi (righe di tabella).

Sono d'accordo che questo sia confuso, e tu non sei il primo ad essere confuso. (Considera l'alternativa, però: aggiungere un wrapper di tipo composito attorno a una singola colonna potrebbe essere ancora più confuso.)

Ma non confuso come quello che succede quando si combinano più funzioni SRF SELECTnell'elenco. Questo cambierà definitivamente con Postgres 10, però:

Il modo più sicuro e meno confuso per entrambi i casi è spostare le funzioni SRF nella FROMclausola. Utilizzare un LATERALjoin se è necessario fare riferimento a colonne di un'altra tabella. Il manuale suggerisce:

La LATERALsintassi produce risultati meno sorprendenti quando si chiamano più funzioni di restituzione di set e in genere dovrebbe essere utilizzata invece.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.