it-swarm.com.de

Setof Record (virtuelle Tabelle) von Funktion zurückgeben

Ich benötige eine Postgres-Funktion, um eine virtuelle Tabelle (wie in Oracle) mit benutzerdefiniertem Inhalt zurückzugeben. Die Tabelle hätte 3 Spalten und eine unbekannte Anzahl von Zeilen.

Ich konnte im Internet einfach nicht die richtige Syntax finden.

Stell dir das vor:

CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" (numeric)
  RETURNS setof record AS
DECLARE
  open_id ALIAS FOR $1;
  returnrecords setof record;
BEGIN
  insert into returnrecords('1', '2', '3');
  insert into returnrecords('3', '4', '5');
  insert into returnrecords('3', '4', '5');
  RETURN returnrecords;
END;

Wie ist das richtig geschrieben?

37
David

(Dies ist alles mit postgresql 8.3.7 getestet - haben Sie eine frühere Version? Schauen Sie sich nur Ihre Verwendung von "ALIAS FOR $ 1" an.)

CREATE OR REPLACE FUNCTION storeopeninghours_tostring(numeric)
 RETURNS SETOF RECORD AS $$
DECLARE
 open_id ALIAS FOR $1;
 result RECORD;
BEGIN
 RETURN QUERY SELECT '1', '2', '3';
 RETURN QUERY SELECT '3', '4', '5';
 RETURN QUERY SELECT '3', '4', '5';
END
$$;

Wenn Sie eine Datensatz- oder Zeilenvariable zurückgeben möchten (anstelle eines Abfrageergebnisses), verwenden Sie "RETURN NEXT" anstelle von "RETURN QUERY".

Um die Funktion aufzurufen, müssen Sie Folgendes tun:

select * from storeopeninghours_tostring(1) f(a text, b text, c text);

Sie müssen also definieren, wie das Ausgabezeilenschema der Funktion in der Abfrage aussehen soll. Um dies zu vermeiden, können Sie Ausgabevariablen in der Funktionsdefinition angeben:

CREATE OR REPLACE FUNCTION storeopeninghours_tostring(open_id numeric, a OUT text, b OUT text, c OUT text)
 RETURNS SETOF RECORD LANGUAGE 'plpgsql' STABLE STRICT AS $$
BEGIN
 RETURN QUERY SELECT '1'::text, '2'::text, '3'::text;
 RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
 RETURN QUERY SELECT '3'::text, '4'::text, '5'::text;
END
$$;

(nicht ganz sicher, warum die extra :: text-Casts erforderlich sind ... '1' ist möglicherweise standardmäßig ein Varchar?)

37
araqnid

Alle zuvor vorhandenen Antworten sind veraltet oder waren anfangs ineffizient.

Angenommen, Sie möchten drei integer Spalten zurückgeben.

PL/pgSQL-Funktion

So machen Sie es mit modernem PL/pgSQL (PostgreSQL 8.4 oder höher):

CREATE OR REPLACE FUNCTION f_foo() -- (open_id numeric) -- parameter not used
  RETURNS TABLE (a int, b int, c int) AS
$func$
BEGIN
RETURN QUERY VALUES
  (1,2,3)
, (3,4,5)
, (3,4,5)
;
END
$func$  LANGUAGE plpgsql IMMUTABLE ROWS 3;

In Postgres 9.6 oder höher können Sie auch PARALLEL SAFE .

Anruf:

SELECT * FROM f_foo();

Hauptpunkte

  • Verwenden RETURNS TABLE um einen Ad-hoc-Zeilentyp zu definieren, der zurückgegeben werden soll.
    Oder RETURNS SETOF mytbl, um einen vordefinierten Zeilentyp zu verwenden.

  • Verwenden RETURN QUERY um mehrere Zeilen mit einem Befehl zurückzugeben.

  • Verwenden Sie einen VALUES Ausdruck, um mehrere Zeilen manuell einzugeben. Dies ist Standard-SQL und hat es schon für immer gegeben.

  • Wenn Sie tatsächlich einen Parameter benötigen, verwenden Sie einen Parameternamen (open_id numeric) anstelle von ALIAS, wovon abgeraten wird . Im Beispiel wurde der Parameter nicht verwendet und nur Rauschen ...

  • Keine Notwendigkeit, vollkommen legale Identifikatoren in doppelte Anführungszeichen zu setzen. Doppelte Anführungszeichen werden nur benötigt, um ansonsten unzulässige Namen (Groß-/Kleinschreibung, unzulässige Zeichen oder reservierte Wörter) zu erzwingen.

  • Die Funktionsvolatilität kann IMMUTABLE sein , da sich das Ergebnis nie ändert.

  • ROWS 3 ist optional, aber da wir wissen wie viele Zeilen zurückgegeben werden, können wir es auch Postgres melden. Kann dem Abfrageplaner bei der Auswahl des besten Plans helfen.

Einfaches SQL

Für einen einfachen Fall wie diesen können Sie stattdessen eine einfache SQL-Anweisung verwenden:

VALUES (1,2,3), (3,4,5), (3,4,5)

Oder wenn Sie bestimmte Spaltennamen und -typen definieren möchten (oder müssen):

SELECT *
FROM  (
   VALUES (1::int, 2::int, 3::int)
        , (3, 4, 5)
        , (3, 4, 5)
   ) AS t(a, b, c);

SQL-Funktion

Sie können es stattdessen in ein einfaches SQL-Funktion verpacken:

CREATE OR REPLACE FUNCTION f_foo()
   RETURNS TABLE (a int, b int, c int) AS
$func$
   VALUES (1, 2, 3)
        , (3, 4, 5)
        , (3, 4, 5);
$func$  LANGUAGE sql IMMUTABLE ROWS 3;
37

Ich benutze temporäre Tabellen ziemlich oft in meinen Funktionen. Sie müssen einen Rückgabetyp in der Datenbank erstellen und dann eine Variable dieses Typs für die Rückgabe erstellen. Unten finden Sie einen Beispielcode, der genau das tut.

CREATE TYPE storeopeninghours_tostring_rs AS
(colone text,
 coltwo text,
 colthree text
);

CREATE OR REPLACE FUNCTION "public"."storeopeninghours_tostring" () RETURNS setof storeopeninghours_tostring_rs AS
$BODY$
DECLARE
  returnrec storeopeninghours_tostring_rs;
BEGIN
    BEGIN 
        CREATE TEMPORARY TABLE tmpopeninghours (
            colone text,
            coltwo text,
            colthree text
        );
    EXCEPTION WHEN OTHERS THEN
        TRUNCATE TABLE tmpopeninghours; -- TRUNCATE if the table already exists within the session.
    END;
    insert into tmpopeninghours VALUES ('1', '2', '3');
    insert into tmpopeninghours VALUES ('3', '4', '5');
    insert into tmpopeninghours VALUES ('3', '4', '5');

    FOR returnrec IN SELECT * FROM tmpopeninghours LOOP
        RETURN NEXT returnrec;
    END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;


select * from storeopeninghours_tostring()
23
Imraan Parker

Für diejenigen, die hier gelandet sind und nach dem MSSQL-Äquivalent suchen, eine temporäre Tabelle zu erstellen und deren Datensätze als Rückgabe auszugeben ... das gibt es in PostgreSQL nicht :( - Sie müssen den Rückgabetyp definieren. Es gibt zwei Möglichkeiten Dies zum Zeitpunkt der Funktionserstellung oder zum Zeitpunkt der Abfrageerstellung.

Siehe hier: http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

8
Brad Holbrook
CREATE OR REPLACE FUNCTION foo(open_id numeric, OUT p1 varchar, OUT p2 varchar, OUT p3 varchar) RETURNS SETOF RECORD AS $$
BEGIN
  p1 := '1'; p2 := '2'; p3 := '3';
  RETURN NEXT; 
  p1 := '3'; p2 := '4'; p3 := '5';
  RETURN NEXT; 
  p1 := '3'; p2 := '4'; p3 := '5';
  RETURN NEXT; 
  RETURN;
END;
$$ LANGUAGE plpgsql;
7
Pavel Stehule