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