Fonction d'assainissement
Ce que vous avez actuellement peut être simplifié/désinfecté pour :
CREATE OR REPLACE FUNCTION func_a (username text = '', databaseobject text = '')
RETURNS ????
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
format ('SELECT * FROM %s v1 LEFT JOIN %I v2 USING (id)'
, CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END
, databaseobject);
END
$func$;
Vous n'avez besoin que d'instances supplémentaires de BEGIN ... END
dans le corps de la fonction pour démarrer des blocs de code séparés avec leur propre portée, ce qui est rarement nécessaire.
L'opérateur de concaténation SQL standard est ||
. +
est un ajout "créatif" de votre ancien fournisseur.
N'utilisez pas d'identificateurs de cas CaMeL à moins que vous ne les citiez entre guillemets. Mieux vaut ne pas les utiliser du tout Voir :
- Les noms de colonne PostgreSQL sont-ils sensibles à la casse ?
varchar(4000)
est également adapté à une limitation spécifique de SQL Server. Il n'a pas de signification spécifique dans Postgres. Utilisez uniquement varchar(4000)
si vous avez réellement besoin d'une limite de 4000 caractères. J'utiliserais simplement text
- sauf que nous n'avons pas besoin de variables du tout ici, après avoir simplifié la fonction.
Si vous n'avez pas utilisé format()
, cependant, consultez le manuel ici.
Type de retour
Maintenant, pour votre question actuelle :le type de retour d'une requête dynamique peut être délicat car SQL exige qu'il soit déclaré au plus tard au moment de l'appel. Si vous avez une table ou une vue ou un type composite dans votre base de données correspondant déjà à la liste de définition de colonne, vous pouvez simplement l'utiliser :
CREATE FUNCTION foo()
RETURNS SETOF my_view AS
...
Sinon, épelez la liste de définition de colonne sans avec (le plus simple) RETURNS TABLE
:
CREATE FUNCTION foo()
RETURNS TABLE (col1 int, col2 text, ...) AS
...
Si vous créez le type de ligne au fur et à mesure, vous pouvez renvoyer des enregistrements anonymes :
CREATE FUNCTION foo()
RETURNS SETOF record AS
...
Mais ensuite, vous devez fournir une liste de définition de colonne à chaque appel, donc je ne l'utilise presque jamais.
Je n'utiliserais pas SELECT *
pour commencer. Utilisez une liste définitive de colonnes à renvoyer et déclarez votre type de retour en conséquence :
CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
RETURNS TABLE(col1 int, col2 text, col3 date)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
format ($f$SELECT v1.col1, v1.col2, v2.col3
FROM %s v1 LEFT JOIN %I v2 USING (id)$f$
, CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END
, databaseobject);
END
$func$;
Pour les requêtes entièrement dynamiques, envisagez de créer la requête dans votre client pour commencer, au lieu d'utiliser une fonction.
Vous devez d'abord comprendre les bases :
- Refactoriser une fonction PL/pgSQL pour renvoyer la sortie de diverses requêtes SELECT
- PL/pgSQL dans le manuel Postgres
Ensuite, il existe des options plus avancées avec des types polymorphes, qui vous permettent de passer le type de retour au moment de l'appel. Plus d'informations dans le dernier chapitre de :
- Refactoriser une fonction PL/pgSQL pour renvoyer la sortie de diverses requêtes SELECT