sql >> Database teknologi >  >> RDS >> PostgreSQL

Returner SETOF rækker fra PostgreSQL-funktionen

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



  1. Sådan fungerer SQLite Count()

  2. Inkluder kolonnenavne i SQLite-forespørgselsresultater

  3. Lær at gemme og analysere dokumenter på Windows filsystem med SQL Server Semantic Search – Del 1

  4. Tilføj ordensindikatoren til en dato i PostgreSQL