2010-12-13 5 views
0

J'ai fait cette fonction plpgsql et cela me rends n'importe quoi! alors que si je sors la partie requête et l'exécute dans une fenêtre sql séparée, elle renvoie les lignes correctes.PLPGSQL distinct sur, ordonné par, ne renvoie rien

Je pense aussi que ne est pas vraiment optimale de requête de sorte que toute aide est appréciée (très nouveau pour plpgsql)

CREATE OR REPLACE FUNCTION get_members(in_company_uuid uuid, in_start integer, in_limit integer, in_sort character varying, in_order character varying, OUT out_status integer, OUT out_status_description character varying, OUT out_value character varying[]) RETURNS SETOF record 
LANGUAGE plpgsql 
AS $$DECLARE 

temp_record RECORD; 
temp_out_value VARCHAR[]; 
temp_iterator INTEGER := 0; 

BEGIN 

FOR temp_record IN EXECUTE ' 
SELECT DISTINCT ON 
(' || in_sort || ') 
u.user_uuid, 
u.firstname, 
u.preposition, 
u.lastname, 
array(SELECT email FROM emails WHERE user_uuid = u.user_uuid) as emails, 
array(SELECT mobilenumber FROM mobilenumbers WHERE user_uuid = u.user_uuid) as mobilenumbers, 
array(SELECT c.name FROM targetgroupusers AS tgu LEFT JOIN membercategories as mc ON mc.targetgroup_uuid = tgu.targetgroup_uuid LEFT JOIN categories AS c ON mc.category_uuid = c.category_uuid WHERE tgu.user_uuid = u.user_uuid) as categories, 
array(SELECT color FROM membercategories WHERE targetgroup_uuid IN(SELECT targetgroup_uuid FROM targetgroupusers WHERE user_uuid = u.user_uuid)) as colors 
FROM 
    membercategories AS mc 
LEFT JOIN 
    targetgroups AS tg 
ON 
    tg.targetgroup_uuid = mc.targetgroup_uuid 
LEFT JOIN 
    targetgroupusers AS tgu 
ON 
    tgu.targetgroup_uuid = tg.targetgroup_uuid 
LEFT JOIN 
    users AS u 
ON 
    u.user_uuid = tgu.user_uuid 
WHERE 
    mc.company_uuid = \'' || in_company_uuid || '\' 
ORDER BY 
    ' || in_sort || ' ' || in_order || ' 
OFFSET 
    ' || in_start || ' 
LIMIT 
    ' || in_limit 

LOOP 
    temp_out_value[temp_iterator] = ARRAY[temp_record.user_uuid::VARCHAR(36), temp_record.firstname::CHARACTER VARYING, temp_record.preposition::CHARACTER VARYING, temp_record.lastname::CHARACTER VARYING, temp_record.emails::CHARACTER VARYING, temp_record.mobilenumbers::CHARACTER VARYING, temp_record.categories::CHARACTER VARYING, temp_record.colors::CHARACTER VARYING]; 
    temp_iterator = temp_iterator+1; 
END LOOP; 

out_status := 0; 
out_status_description := 'Members retrieved'; 
out_value := temp_out_value; 
RETURN; 

END$$; 

Merci beaucoup!

+0

Avez-vous besoin de retourner les champs de statut car ils sont juste des constantes? –

Répondre

1

Vous avez besoin d'utiliser RETURN NEXT temp_record au lieu de "juste" RETOUR afin de retourner un jeu de résultats complet.

Ceci est la partie du manuel qui explique comment gérer une fonction « RETOUR SETOF »:

Dans ce cas, les éléments individuels de retour sont définis par une séquence de RETURN NEXT ou retourner les commandes de requête , puis est utilisé une commande de déclaration finale sans argument pour indiquer que la fonction a terminé son exécution

+0

Comme vous pouvez le voir j'ai fait mon propre format de sortie (out_status, out_status_description, out_value) c'est pourquoi je l'ai mis dans un tableau d'abord – Koen

+1

Vous ne pouvez pas utiliser "RETURNS SETOF" sans utiliser RETURN NEXT. Vous devez donc créer une variable qui contient les enregistrements que vous voulez retourner avec RETOUR SUIVANT –

+0

Merci beaucoup! – Koen

0

ne pas utiliser \ pour échapper, utilisez les guillemets:

\'' || in_company_uuid || '\' 

''' || in_company_uuid || ''' 

Mais, je ne voudrais pas utiliser la fonction pour cela, juste une requête SQL simple. Utilisez EXPLAIN pour voir comment il est exécuté et où les problèmes de performance peuvent être trouvés. Ce n'est pas un très bon morceau de SQL ...

Ps. Votre fonction est également vulnérable à l'injection SQL, vous mettez userinput sans s'échapper dans le SQL.

+0

je l'ai changé à votre suggestion, il ne marche pas retourner des erreurs, mais pas non plus un résultat, donc pas out_status, out_status_description et out_value – Koen

0

Vous devez utiliser

CREATE OR REPLACE FUNCTION get_members(...) RETURNS record LANGUAGE plpgsql AS 
... 

-à-dire enlever la setof qui est votre problème a_horse mentionne

Mais gardez à l'esprit que votre obtenir seulement 1 rang comme celui-ci. Vous pouvez unnest ce tableau si vous voulez plusieurs lignes en suivant cet exemple:

create or replace function unnest(anyarray) returns setof anyelement as $$ 
    select $1[i] from generate_series(array_lower($1,1), array_upper($1,1)) i; 
$$ language'sql' immutable; 

create function func(out text, out text[]) returns record language plpgsql as $$ 
begin 
    $1='success'; 
    $2[1]='hello'; 
    $2[2]='there'; 
    $2[3]='Koen'; 
    return; 
end;$$; 

select * from unnest((select column2 from func())); 

unnest 
-------- 
hello 
there 
Koen 

Si vous êtes sur 8,4 ou au-dessus alors il n'y a pas besoin de créer votre propre fonction unnest comme je l'ai fait ici.

+0

Je pense que Koen * ne * veulent utiliser « retours SETOF », il/elle a juste besoin d'utiliser « retour prochain "avec la définition d'enregistrement appropriée pour récupérer plus d'une ligne de la fonction –

+0

@a_horse Je ne suis pas si sûr - il a 3 paramètres' out', un seul est un tableau, les autres sont liés à l'état. Pas comme je le ferais, mais bon ... –

Questions connexes