sql >> Database >  >> RDS >> PostgreSQL

Functie om een ​​dynamische set kolommen voor een bepaalde tabel te retourneren

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 en table_name als parameters om te functioneren en een recordlijst te krijgen, volgens column_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?
terzijde

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.



  1. ID ophalen van een voorwaardelijke INSERT

  2. Hoe Oracle ORDER BY en ROWNUM correct te gebruiken?

  3. Is er een manier om geen vierkante haken te gebruiken in SQL Server?

  4. Kruistabel met een groot of ongedefinieerd aantal categorieën