Desinficeringsfunktion
Det, du har i øjeblikket, kan forenkles / renses til:
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 kun yderligere forekomster af BEGIN ... END
i funktionslegemet for at starte separate kodeblokke med deres eget omfang, hvilket sjældent er nødvendigt.
Standard SQL-sammenkædningsoperatoren er ||
. +
er en "kreativ" tilføjelse af din tidligere leverandør.
Brug ikke CaMeL-case-identifikatorer, medmindre du citerer dem dobbelt. Bedst ikke at bruge dem overhovedet Se:
- Er PostgreSQL-kolonnenavne skelne mellem store og små bogstaver?
varchar(4000)
er også skræddersyet til en specifik begrænsning af SQL Server. Det har ingen specifik betydning i Postgres. Brug kun varchar(4000)
hvis du rent faktisk har brug for en grænse på 4000 tegn. Jeg ville bare bruge text
- bortset fra at vi ikke behøver nogen variable slet her, efter at have forenklet funktionen.
Hvis du ikke har brugt format()
, men se vejledningen her.
Returtype
Nu til dit egentlige spørgsmål:Returtypen for en dynamisk forespørgsel kan være vanskelig, da SQL kræver, at den erklæres senest ved opkaldstidspunktet. Hvis du har en tabel eller visning eller sammensat type i din database, der allerede matcher kolonnedefinitionslisten, kan du bare bruge det:
CREATE FUNCTION foo()
RETURNS SETOF my_view AS
...
Ellers stave kolonnedefinitionslisten uden med (simpelste) RETURNS TABLE
:
CREATE FUNCTION foo()
RETURNS TABLE (col1 int, col2 text, ...) AS
...
Hvis du øger rækketypen, mens du går, kan du returnere anonyme poster:
CREATE FUNCTION foo()
RETURNS SETOF record AS
...
Men så skal du give en kolonnedefinitionsliste med hvert opkald, så det bruger jeg næsten aldrig.
Jeg ville ikke bruge SELECT *
til at starte med. Brug en endelig liste over kolonner til at returnere og erklære din returtype i overensstemmelse hermed:
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$;
For helt dynamiske forespørgsler kan du overveje at bygge forespørgslen i din klient til at begynde med i stedet for at bruge en funktion.
Du skal først forstå det grundlæggende:
- Refaktorer en PL/pgSQL-funktion for at returnere output fra forskellige SELECT-forespørgsler
- PL/pgSQL i Postgres-manualen
Så er der mere avancerede muligheder med polymorfe typer, som giver dig mulighed for at videregive returtypen på opkaldstidspunktet. Mere i sidste kapitel af:
- Refaktorer en PL/pgSQL-funktion for at returnere output fra forskellige SELECT-forespørgsler