2017-09-24 8 views
1

Je dois créer une fonction qui renvoie les résultats d'une requête SELECT. Cette requête SELECT est une JOIN de quelques tables temporaires créées à l'intérieur de cette fonction. Est-il possible de créer une telle fonction? Voici un exemple (il est très simplifié, en réalité, il y a plusieurs tables temporaires avec de longues requêtes):Créer une fonction avec des tables temporaires qui renvoient une requête de sélection à l'aide de ces tables temporaires

CREATE OR REPLACE FUNCTION myfunction() RETURNS TABLE (column_a TEXT, column_b TEXT) AS $$ 
BEGIN 
CREATE TEMPORARY TABLE raw_data ON COMMIT DROP 
AS 
SELECT d.column_a, d2.column_b FROM dummy_data d JOIN dummy_data_2 d2 using (id); 

RETURN QUERY (select distinct column_a, column_b from raw_data limit 100); 
END; 
$$ 
LANGUAGE 'plpgsql' SECURITY DEFINER 

J'obtiens l'erreur:

[Error] Script lines: 1-19 ------------------------- 
ERROR: RETURN cannot have a parameter in function returning set; 
use RETURN NEXT at or near "QUERY"Position: 237 

je présenter des excuses à l'avance pour des erreurs évidentes, je Je suis nouveau à ça.

la version Psql est PostgreSQL 8.2.15 (Greenplum Database 4.3.12.0 build 1)

+0

Intéressant. Quelle est l'erreur que vous obtenez? –

+0

J'ai tapé votre code dans SQLFiddle et avec quelques trucs syntaxiques qui pourraient ou non être pertinents pour votre cas, il semble passer les vérifications et retourner le résultat attendu http://sqlfiddle.com/#!15/874fa/1 –

+0

Vous avez oublié de fournir votre version de Postgres, ce qui est essentiel. Et «ne semble pas pouvoir le faire fonctionner» n'est pas un message d'erreur dont j'ai déjà entendu parler. BTW, il n'y a pas de "fonctions psql". Le vôtre est une fonction de plpgsql. Enfin: qu'est-ce qui vous fait penser que vous avez besoin de tables temporaires pour cela? Ou même une fonction? –

Répondre

1

L'erreur la plus probable cela pourrait augmenter dans Postgres:

ERROR: column "foo" specified more than once

Signification, il y a au moins un plus de nom de colonne (autre que id qui est replié sur une instance avec la clause USING) inclus dans les deux tables. Cela ne déclencherait pas une exception dans un SQL SELECT qui tolère les noms de colonne de sortie en double. Mais vous ne pouvez pas créer une table avec des noms en double.

Le problème est aussi valable pour Greenplum (comme vous avez déclaré plus tard), qui est pas Postgres. Il a été dérivé de PostgreSQL en 2005 et développé séparément. Le manuel Postgres actuel ne s'applique plus du tout. Regardez au Greenplum documentation.

Et psql est juste le programme terminal interactif standard de PostgreSQL. Évidemment, vous utilisez celui fourni avec PostgreSQL 8.2.15, mais le SGBDR est toujours Greenplum, pas Postgres.

Syntaxe fix (pour Postgres, comme vous devez d'abord tagged toujours d'actualité):

CREATE OR REPLACE FUNCTION myfunction() 
    RETURNS TABLE (column_a text, column_b text) AS 
$func$ 
BEGIN 
    CREATE TEMPORARY TABLE raw_data ON COMMIT DROP AS 
    SELECT d.column_a, d2.column_b -- explicit SELECT list avoids duplicate column names 
    FROM dummy_data d 
    JOIN dummy_data_2 d2 using (id); 

    RETURN QUERY 
    SELECT DISTINCT column_a, column_b 
    FROM raw_data 
    LIMIT 100; 
END 
$func$ LANGUAGE plpgsql SECURITY DEFINER; 

L'exemple aurait pas besoin d'une table temporaire - à moins que vous accédez à la table temporaire après l'appel de fonction dans la même transaction (ON COMMIT DROP). Sinon, une fonction SQL simple est meilleure dans tous les sens. Syntaxe pour Postgres et Greenplum:

CREATE OR REPLACE FUNCTION myfunction(OUT column_a text, OUT column_b text) 
    RETURNS SETOF record AS 
$func$ 
    SELECT DISTINCT d.column_a, d2.column_b 
    FROM dummy_data d 
    JOIN dummy_data_2 d2 using (id) 
    LIMIT 100; 
$func$ LANGUAGE plpgsql SECURITY DEFINER; 

Pas moins, it should also work for Greenplum.

La seule raison restante pour cette fonction est SECURITY DEFINER. Sinon, vous pouvez simplement utiliser l'instruction SQL simple (éventuellement en tant qu'instruction préparée) à la place.

RETURN QUERY a été ajouté à PL/pgSQL avec la version 8.3 en 2008, certaines années après la fourche de Greenplum. Pourrait expliquer votre msg d'erreur:

ERROR: RETURN cannot have a parameter in function returning set; 
use RETURN NEXT at or near "QUERY" Position: 237 

En plus: LIMIT sans ORDER BY produit des résultats arbitraires. Je suppose que vous êtes au courant de cela.


Si pour une raison quelconque vous avez besoin en fait des tables temporaires et ne peut pas passer à Greenplum 5.0 like A. Scherbaum suggested, vous pouvez toujours le faire fonctionner dans Greenplum 4.3.x (comme dans Postgres 8.2). Utilisez une boucle FOR en combinaison avec RETURN NEXT.
Exemples:

2

La version la plus récente de Greenplum Database (5.0) est basée sur PostgreSQL 8.3, et il prend en charge la syntaxe RETOUR QUERY. Juste testé votre fonction sur:

PostgreSQL 8.4devel (Greenplum Database 5.0.0-beta.10+dev.726.gd4a707c762 build dev)