Oplossing voor het eenvoudige geval
Zoals uitgelegd in de antwoorden waarnaar hieronder wordt verwezen, kunt u geregistreerde (rij) typen gebruiken en dus impliciet het retourtype van een polymorfe functie declareren:
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;
Bel:
SELECT * FROM public.get_table(NULL::public.users); -- note the syntax!
Geeft de volledige tabel terug (met alle gebruikerskolommen).
Wacht! Hoe?
Gedetailleerde uitleg in dit gerelateerde antwoord, hoofdstuk"Verschillende complete tabeltypes" :
- Refactor een PL/pgSQL-functie om de uitvoer van verschillende SELECT-query's te retourneren
TABLE foo
is gewoon een afkorting voor SELECT * FROM foo
:
- Is er een snelkoppeling voor SELECT * FROM?
2 stappen voor een volledig dynamisch retourtype
Maar wat u probeert te doen is strikt onmogelijk in een enkele SQL-opdracht.
Ik wil
schema_name
doorgeven entable_name
als parameters om te functioneren en een recordlijst te krijgen, volgenscolumn_visible
veld inpublic.fields
tafel.
Er is geen directe manier om een willekeurige selectie van kolommen te retourneren (retourtype niet bekend op het moment van aanroepen) van een functie - of elke SQL-opdracht. SQL vereist om het aantal, namen en typen resulterende kolommen te weten tijdens de oproep. Meer in het 2e hoofdstuk van dit gerelateerde antwoord:
- Hoe genereer ik een gedraaide CROSS JOIN waarvan de resulterende tabeldefinitie onbekend is?
Er zijn verschillende oplossingen . U kunt het resultaat in een van de standaard documenttypen plaatsen (json
, jsonb
, hstore
, xml
).
Of je genereert de query met één functieaanroep en voert het resultaat uit met de volgende:
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;
Bel:
SELECT public.generate_get_table('public', 'users');
Dit creëert een query van het formulier:
SELECT usr_id, usr FROM public.users;
Voer het uit in de 2e stap. (Misschien wilt u kolomnummers toevoegen en kolommen bestellen.)
Of voeg \gexec
toe in psql om de retourwaarde onmiddellijk uit te voeren. Zie:
Hoe evaluatie van subquery te forceren voordat u zich aansluit bij / naar een buitenlandse server duwt
Zorg ervoor dat u zich verdedigt tegen SQL-injectie:
- INSERT met dynamische tabelnaam in triggerfunctie
- Definieer tabel- en kolomnamen als argumenten in een plpgsql-functie?
varchar(100)
heeft niet veel zin voor identifiers, die beperkt zijn tot 63 tekens in standaard Postgres:
- Maximum aantal tekens in labels (tabelnamen, kolommen enz.)
Als u begrijpt hoe het object-ID type regclass
werkt, kunt u de schema- en tabelnaam vervangen door een enkele regclass
kolom.