Présentation de Set Returning Function (SRF) dans la liste SELECT

8

Pourquoi existe-t-il une différence de comportement entre l'utilisation d'une fonction de retour définie (SRF) dans la liste SELECT et l'utilisation de SRF dans la clause FROM?

Par exemple, pour un SRF simple renvoyant 2 lignes:

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(); renvoie deux lignes de colonne unique contenant chacune un enregistrement:

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

Alors que SELECT * FROM gen_series();renvoie deux lignes avec l'enregistrement développé:

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

Par comparaison, si le SRF renvoie une seule colonne, l'appel de SRF dans la clause SELECT ou FROM ne fait aucune différence. par exemple:

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

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

Mes questions sont:

  1. Je ne vois pas très bien pourquoi dans le deuxième cas, le comportement SRF est différent du premier cas simplement parce que la table retournée a une seule colonne. Ce comportement est-il vraiment cohérent en termes de types, tuples et ensembles?

  2. Quelle est la différence entre les deux cas qui conduit au comportement différent?

  3. Les SRF peuvent être utilisés comme des tableaux comme indiqué ci-dessus, mais les tableaux peuvent-ils également être utilisés pour remplacer les SRF? par exemple

    SELECT my_table; 

Apparemment, cela ne peut pas être fait, mais pourquoi est-ce SELECT my_SRF();possible, alors que ce SELECT my_table;n'est pas permis (en termes de relations et de mathématiques)?

tinlyx
la source
SELECT my_table;n'est pas une syntaxe valide
Mladen Uzelac

Réponses:

3

Postgres traite différemment le cas simple. Plusieurs colonnes sont traitées comme du type composite (ligne de tableau), qui est uniquement décomposé SELECT * FROM ..., tandis qu'une seule colonne de type scalaire est traitée comme cela, sans encapsuleur de type composite ajouté. Produit donc SELECT my_SRF()la même chose que SELECT * FROM my_SRF()pour le cas simple. Le manuel sur les fonctions de table :

Les fonctions de table sont des fonctions qui produisent un ensemble de lignes, composé de types de données de base (types scalaires) ou de types de données composites (lignes de table).

Je suis d'accord que cela prête à confusion, et vous n'êtes pas le premier à être confus. (Considérez l'alternative, cependant: l'ajout d'un wrapper de type composite autour d'une seule colonne peut être encore plus déroutant.)

Mais pas aussi confus que ce qui se passe lorsque vous combinez plusieurs fonctions SRF dans la SELECTliste. Cela va changer avec Postgres 10 pour de bon, cependant:

Le moyen sûr et moins déroutant pour l'un ou l'autre cas est de déplacer les fonctions SRF vers la FROMclause. Utilisez une LATERALjointure si vous devez faire référence à des colonnes d'une autre table. Le manuel suggère:

La LATERALsyntaxe produit des résultats moins surprenants lors de l'appel de plusieurs fonctions de retour d'ensemble, et devrait généralement être utilisée à la place.

Erwin Brandstetter
la source