3 votes

Sélection d'une fonction PostgreSQL qui renvoie un type composite

Comment inclure une fonction qui renvoie un type composite dans une SELECT ?
Je suis de type composite :

CREATE TYPE public.dm_nameid AS (
  id   public.dm_int,
  name public.dm_str
);

De plus, j'ai une fonction qui renvoie ce type de données fn_GetLinkedProject(integer) . Et j'ai besoin de faire quelque chose comme ça :

SELECT 
    p.id, p.data, p.name, 
    pl.id linked_id, pl.name linked_name
FROM tb_projects p
   left join "fn_GetLinkedProject"(p.id) pl

Comment puis-je le faire ?

J'ai lu ce article.

Je ne veux pas suivre la méthode :

SELECT
 p.id, p.data, p.name, 
    (select pl1.id from "fn_GetLinkedProject"(p.id) pl1 ) linked_id,
    (select pl2.name from "fn_GetLinkedProject"(p.id) pl2 ) linked_name
FROM tb_projects p

8voto

Erwin Brandstetter Points 110228

Postgres 9.3 ou plus récent

Utilisez un LATERAL rejoignez-nous !

SELECT p.id, p.name, p.data, f.*
FROM   tb_projects p
LEFT   JOIN LATERAL fn_getlinkedproject(p.id) f(linked_id, lined_name) ON TRUE;

Résultat :

 id |  data  |  name  | linked_id | linked_name
----+--------+--------+-----------+-------------
  1 | data_1 | name_1 |         2 | name_2
  2 | data_2 | name_2 |         3 | name_3
  3 | data_3 | name_3 |         1 | name_1

Voir :

Postgres 9.2 ou plus ancien

Inférieur pour plusieurs raisons. Attacher des alias de colonnes n'est pas aussi simple. Il faut plutôt renommer d'autres noms conflictuels :

SELECT p.id AS p_id, p.data AS p_data, p.name AS p_name, (fn_getlinkedproject(p.id)).*
FROM   tb_projects p;

Résultat :

 p_id | p_data | p_name | id |  name
------+--------+--------+----+--------
    1 | data_1 | name_1 |  2 | name_2
    2 | data_2 | name_2 |  3 | name_3
    3 | data_3 | name_3 |  1 | name_1

A renommer les colonnes de résultats, vous devez le faire :

SELECT p.id, p.data, p.name
     ,(fn_getlinkedproject(p.id)).id   AS linked_id
     ,(fn_getlinkedproject(p.id)).name AS linked_name
FROM   tb_projects p;

Les deux anciennes solutions aboutissent au même (mauvais) plan de requête consistant à appeler la fonction à plusieurs reprises.

Pour éviter cela, utilisez une sous-requête :

SELECT p.id, p.data, p.name
    , (p.x).id AS linked_id, (p.x).name AS linked_name
FROM  (SELECT *, fn_getlinkedproject(id) AS x FROM tb_projects) p;

Notez le placement des éléments essentiels parenthèses .
Lire l'article manuel sur les types de composites .

Démo

CREATE TYPE dm_nameid AS (
  id   int
, name text); -- types simplified for demo

CREATE TABLE tb_projects(
  id   int
, data text
, name text);

INSERT INTO tb_projects VALUES
  (1, 'data_1', 'name_1')
, (2, 'data_2', 'name_2')
, (3, 'data_3', 'name_3');

CREATE function fn_getlinkedproject(integer)  -- avoiding CaMeL-case for demo
  RETURNS dm_nameid LANGUAGE sql AS
'SELECT id, name FROM tb_projects WHERE id = ($1 % 3) + 1';

_db<>fidèle aquí_

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X