sql >> Databasteknik >  >> RDS >> PostgreSQL

Returnera SETOF rader från PostgreSQL-funktionen

Desinficeringsfunktion

Det du för närvarande har kan förenklas/saneras till:

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$;

Du behöver bara ytterligare instanser av BEGIN ... END i funktionskroppen för att starta separata kodblock med eget omfång, vilket sällan behövs.

Standardoperatorn för SQL-konkatenering är || . + är ett "kreativt" tillägg av din tidigare leverantör.

Använd inte CaMeL-case-identifierare om du inte dubbelciterar dem. Bäst att inte använda dem alls Se:

  • Är PostgreSQL-kolumnnamn skiftlägeskänsliga?

varchar(4000) är också skräddarsydd för en specifik begränsning av SQL Server. Det har ingen specifik betydelse i Postgres. Använd endast varchar(4000) om du faktiskt behöver en gräns på 4000 tecken. Jag skulle bara använda text - förutom att vi inte behöver några variabler alls här, efter att ha förenklat funktionen.

Om du inte har använt format() , ändå, se manualen här.

Returtyp

Nu, till din faktiska fråga:Returtypen för en dynamisk fråga kan vara knepig eftersom SQL kräver att den deklareras senast vid anropstid. Om du har en tabell eller vy eller sammansatt typ i din databas som redan matchar kolumndefinitionslistan kan du bara använda det:

CREATE FUNCTION foo()
  RETURNS SETOF my_view AS
...

Annars, stava kolumndefinitionslistan utan med (enklast) RETURNS TABLE :

CREATE FUNCTION foo()
  RETURNS TABLE (col1 int, col2 text, ...) AS
...

Om du utökar radtypen allt eftersom kan du returnera anonyma poster:

CREATE FUNCTION foo()
  RETURNS SETOF record AS
...

Men då måste du tillhandahålla en kolumndefinitionslista med varje samtal, så det använder jag nästan aldrig.

Jag skulle inte använda SELECT * till att börja med. Använd en definitiv lista med kolumner för att returnera och deklarera din returtyp i enlighet med detta:

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$;

För helt dynamiska frågor, överväg att bygga frågan i din klient till att börja med, istället för att använda en funktion.

Du måste först förstå grunderna:

  • Refaktorera en PL/pgSQL-funktion för att returnera utdata från olika SELECT-frågor
  • PL/pgSQL i Postgres manual

Sedan finns det mer avancerade alternativ med polymorfa typer, som låter dig passera returtypen vid samtalstid. Mer i det sista kapitlet av:

  • Refaktorera en PL/pgSQL-funktion för att returnera utdata från olika SELECT-frågor



  1. UPPDATERINGAR till statistik

  2. Välja rader ordnade efter någon kolumn och distinkta i en annan

  3. ORA-4031-fel med Direct NFS

  4. C#:Oracle Data Type Equivalence med OracleDbType