Solution pour le cas simple
Comme expliqué dans les réponses référencées ci-dessous, vous pouvez utiliser des types enregistrés (lignes) et ainsi déclarer implicitement le type de retour d'une fonction polymorphe :
CREATE OR REPLACE FUNCTION public.get_table(_tbl_type anyelement)
RETURNS SETOF anyelement AS
$func$
BEGIN
RETURN QUERY EXECUTE format('TABLE %s', pg_typeof(_tbl_type));
END
$func$ LANGUAGE plpgsql;
Appel :
SELECT * FROM public.get_table(NULL::public.users); -- note the syntax!
Renvoie le tableau complet (avec toutes les colonnes utilisateur).
Attendez ! Comment ?
Explication détaillée dans cette réponse connexe, chapitre"Divers types de tableaux complets" :
- Refactoriser une fonction PL/pgSQL pour renvoyer la sortie de diverses requêtes SELECT
TABLE foo
est juste l'abréviation de SELECT * FROM foo
:
- Existe-t-il un raccourci pour SELECT * FROM ?
2 étapes pour un type de retour entièrement dynamique
Mais ce que vous essayez de faire est strictement impossible dans un simple Commande SQL.
Je veux transmettre
schema_name
ettable_name
comme paramètres pour fonctionner et obtenir la liste des enregistrements, seloncolumn_visible
champ danspublic.fields
tableau.
Il n'existe aucun moyen direct de renvoyer une sélection arbitraire de colonnes (type de retour inconnu au moment de l'appel) à partir d'une fonction - ou any Commande SQL. SQL exige de connaître le nombre, les noms et les types de colonnes résultantes au moment de l'appel. Plus d'informations dans le 2ème chapitre de cette réponse connexe :
- Comment puis-je générer un CROSS JOIN pivoté où la définition de table résultante est inconnue ?
Il existe différentes solutions de contournement . Vous pouvez envelopper le résultat dans l'un des types de documents standard (json
, jsonb
, hstore
, xml
).
Ou vous générez la requête avec un appel de fonction et exécutez le résultat avec le suivant :
CREATE OR REPLACE FUNCTION public.generate_get_table(_schema_name text, _table_name text)
RETURNS text AS
$func$
SELECT format('SELECT %s FROM %I.%I'
, string_agg(quote_ident(column_name), ', ')
, schema_name
, table_name)
FROM fields
WHERE column_visible
AND schema_name = _schema_name
AND table_name = _table_name
GROUP BY schema_name, table_name
ORDER BY schema_name, table_name;
$func$ LANGUAGE sql;
Appel :
SELECT public.generate_get_table('public', 'users');
Cela crée une requête de la forme :
SELECT usr_id, usr FROM public.users;
Exécutez-le dans la 2ème étape. (Vous pouvez ajouter des numéros de colonne et ordonner les colonnes.)
Ou ajoutez \gexec
dans psql pour exécuter la valeur de retour immédiatement. Voir :
Comment forcer l'évaluation d'une sous-requête avant de rejoindre/pousser vers un serveur étranger
Assurez-vous de vous défendre contre l'injection SQL :
- INSERT avec le nom de la table dynamique dans la fonction de déclenchement
- Définir les noms de table et de colonne comme arguments dans une fonction plpgsql ?
varchar(100)
n'a pas beaucoup de sens pour les identifiants, qui sont limités à 63 caractères dans Postgres standard :
- Nombre maximal de caractères dans les libellés (noms de table, colonnes, etc.)
Si vous comprenez comment le type d'identifiant d'objet regclass
fonctionne, vous pouvez remplacer le schéma et le nom de la table par un seul regclass
colonne.