J'ai besoin d'une fonction Postgres pour retourner une table virtuelle (comme dans Oracle) avec un contenu personnalisé. Le tableau aurait 3 colonnes et un nombre inconnu de lignes.
Je n'arrivais tout simplement pas à trouver la syntaxe correcte sur Internet.
Imagine ça:
CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" (numeric)
RETURNS setof record AS
DECLARE
open_id ALIAS FOR $1;
returnrecords setof record;
BEGIN
insert into returnrecords('1', '2', '3');
insert into returnrecords('3', '4', '5');
insert into returnrecords('3', '4', '5');
RETURN returnrecords;
END;
Comment est-ce écrit correctement?
(Tout cela est testé avec postgresql 8.3.7 - avez-vous une version antérieure? Il suffit de regarder votre utilisation de "ALIAS FOR $ 1")
CREATE OR REPLACE FUNCTION storeopeninghours_tostring(numeric)
RETURNS SETOF RECORD AS $$
DECLARE
open_id ALIAS FOR $1;
result RECORD;
BEGIN
RETURN QUERY SELECT '1', '2', '3';
RETURN QUERY SELECT '3', '4', '5';
RETURN QUERY SELECT '3', '4', '5';
END
$$;
Si vous avez un enregistrement ou une variable de ligne à renvoyer (au lieu d'un résultat de requête), utilisez "RETOUR SUIVANT" plutôt que "RETOUR QUESTION".
Pour appeler la fonction, vous devez faire quelque chose comme:
select * from storeopeninghours_tostring(1) f(a text, b text, c text);
Vous devez donc définir ce que vous attendez du schéma de ligne de sortie de la fonction dans la requête. Pour éviter cela, vous pouvez spécifier des variables de sortie dans la définition de fonction:
CREATE OR REPLACE FUNCTION storeopeninghours_tostring(open_id numeric, a OUT text, b OUT text, c OUT text)
RETURNS SETOF RECORD LANGUAGE 'plpgsql' STABLE STRICT AS $$
BEGIN
RETURN QUERY SELECT '1'::text, '2'::text, '3'::text;
RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
END
$$;
(je ne sais pas trop pourquoi les transtypages extra :: text sont requis ... '1' est un varchar par défaut peut-être?)
Toutes les réponses déjà existantes sont obsolètes ou étaient inefficaces au départ.
En supposant que vous souhaitiez renvoyer trois colonnes integer
.
Voici comment procéder avec PL/pgSQL moderne (PostgreSQL 8.4 ou version ultérieure):
CREATE OR REPLACE FUNCTION f_foo() -- (open_id numeric) -- parameter not used
RETURNS TABLE (a int, b int, c int) AS
$func$
BEGIN
RETURN QUERY VALUES
(1,2,3)
, (3,4,5)
, (3,4,5)
;
END
$func$ LANGUAGE plpgsql IMMUTABLE ROWS 3;
Dans Postgres 9.6 ou version ultérieure, vous pouvez également ajouter PARALLEL SAFE
.
Appel:
SELECT * FROM f_foo();
Utilisation RETURNS TABLE
pour définir un type de ligne ad hoc à renvoyer.
Ou RETURNS SETOF mytbl
pour utiliser un type de ligne prédéfini.
Utilisation RETURN QUERY
pour renvoyer plusieurs lignes avec une seule commande.
Utilisez une expression VALUES
pour saisir manuellement plusieurs lignes. Ceci est du SQL standard et existe depuis toujours pour toujours.
Si vous avez réellement besoin d'un paramètre, utilisez un nom de paramètre (open_id numeric)
au lieu de ALIAS
, ce qui est déconseillé . Dans l'exemple le paramètre n'a pas été utilisé et juste du bruit ...
Pas besoin de citer deux fois des identifiants parfaitement légaux. Les guillemets doubles sont uniquement nécessaires pour forcer les noms autrement illégaux (casse mixte, caractères illégaux ou mots réservés).
La volatilité des fonctions peut être IMMUTABLE
, car le résultat ne change jamais.
ROWS 3
est facultatif, mais comme nous - savons combien de lignes sont retournées, nous pourrions aussi bien le déclarer à Postgres. Peut aider le planificateur de requêtes à choisir le meilleur plan.
Pour un cas simple comme celui-ci, vous pouvez utiliser une instruction SQL simple à la place:
VALUES (1,2,3), (3,4,5), (3,4,5)
Ou, si vous souhaitez (ou avez) définir des noms et des types de colonnes spécifiques:
SELECT *
FROM (
VALUES (1::int, 2::int, 3::int)
, (3, 4, 5)
, (3, 4, 5)
) AS t(a, b, c);
Vous pouvez l'envelopper dans un simple fonction SQL à la place:
CREATE OR REPLACE FUNCTION f_foo()
RETURNS TABLE (a int, b int, c int) AS
$func$
VALUES (1, 2, 3)
, (3, 4, 5)
, (3, 4, 5);
$func$ LANGUAGE sql IMMUTABLE ROWS 3;
J'utilise pas mal de tables temporaires dans mes fonctions. Vous devez créer un type de retour sur la base de données, puis créer une variable de ce type à renvoyer. Voici un exemple de code qui fait exactement cela.
CREATE TYPE storeopeninghours_tostring_rs AS
(colone text,
coltwo text,
colthree text
);
CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" () RETURNS setof storeopeninghours_tostring_rs AS
$BODY$
DECLARE
returnrec storeopeninghours_tostring_rs;
BEGIN
BEGIN
CREATE TEMPORARY TABLE tmpopeninghours (
colone text,
coltwo text,
colthree text
);
EXCEPTION WHEN OTHERS THEN
TRUNCATE TABLE tmpopeninghours; -- TRUNCATE if the table already exists within the session.
END;
insert into tmpopeninghours VALUES ('1', '2', '3');
insert into tmpopeninghours VALUES ('3', '4', '5');
insert into tmpopeninghours VALUES ('3', '4', '5');
FOR returnrec IN SELECT * FROM tmpopeninghours LOOP
RETURN NEXT returnrec;
END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
select * from storeopeninghours_tostring()
Pour ceux qui ont atterri ici à la recherche de l'équivalent MSSQL de création d'une table temporaire et de vidage de ses enregistrements en tant que retour ... qui n'existe pas dans PostgreSQL :( - vous devez définir le type de retour. Il y a deux façons de faire ceci, au moment de la création de la fonction ou au moment de la création de la requête.
Voir ici: http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions
CREATE OR REPLACE FUNCTION foo(open_id numeric, OUT p1 varchar, OUT p2 varchar, OUT p3 varchar) RETURNS SETOF RECORD AS $$
BEGIN
p1 := '1'; p2 := '2'; p3 := '3';
RETURN NEXT;
p1 := '3'; p2 := '4'; p3 := '5';
RETURN NEXT;
p1 := '3'; p2 := '4'; p3 := '5';
RETURN NEXT;
RETURN;
END;
$$ LANGUAGE plpgsql;