Fehler: set_valued-Funktion, die im Kontext aufgerufen wird und keine Menge akzeptieren kann. Worum geht es?

11

Ich benutze Postgresql 9.1 mit Ubuntu 12.04.

Inspiriert von Craig Antwort auf meine Frage Verkettung von SETOF Typ oder SETOF Rekord Ich dachte , ich würde gut gehen mit der Verwendung return query, setof recordund eine Reihe Generator in diese plpgsql Funktion:

create or replace function compute_all_pair_by_craig(id_obj bigint)
    returns setof record as $$
begin
    return query select o.id, generate_series(0,o.value) from m_obj as o;     
end;
$$    language plpgsql;

Während der Ausführung erhalte ich den Fehler:

ERROR: set_valued function called in context that cannot accept a set

Was ist falsch ? Im Gegensatz zu Craig fordere ich die Funktion auf, zurückzukehren setof record.

Ich kann etwas erreichen, das genau wie Craig create type pair_id_value as (idx bigint, value integer)funktioniert , dh indem ich einen Typ definiere und meine plpgsql-Funktion a setof of pair_id_valueanstelle von a zurückgibt setof record.

Aber selbst mit dieser funktionierenden Lösung verstehe ich immer noch nicht, warum select id, generate_series(0,13)allein ein Ergebnis in zwei Spalten zurückgegeben wird ... und im Gegenteil, wenn die Funktion (gibt setof pair_id_value zurück) mit return query select id, generate_series(0,my_obj.value) from my_objein Ergebnis in nur einer Spalte zurückgibt , wie das Feld aussieht diese (123123,0) (123123,1) (123123,2) (3 Zeilen), die offensichtlich Tupel sind.

Ist es ein Fall, in dem eine temporäre Tabelle erstellt werden muss / sollte?

Stephane Rolland
quelle
Das kann nicht der genaue Text der Funktion sein, die Sie ausführen, da sie nicht kompiliert wird. Es gibt ein überschüssiges Semikolon nach BEGINund ein fehlendes nach dem RETURN QUERY. Nachdem ich diese Fehler korrigiert habe, bestätige ich den Fehler bei der Rücksendung record. wird in Antwort erklären.
Craig Ringer
@CraigRinger Ich habe das Semikolon wieder angebracht.
Stephane Rolland

Antworten:

7

Die Fehlermeldung ist nicht sehr hilfreich:

regress=> SELECT * FROM  compute_all_pair_by_craig(100);
ERROR:  a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM  compute_all_pair_by_craig(100);

Wenn Sie die Abfrage jedoch umformulieren, um sie als ordnungsgemäße Set-Return-Funktion aufzurufen, sehen Sie das eigentliche Problem:

regress=> SELECT * FROM compute_all_pair_by_craig(100);
ERROR:  a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM compute_all_pair_by_craig(100);

Wenn Sie SETOF RECORDohne OUTParameterliste verwenden, müssen Sie die Ergebnisse in der aufrufenden Anweisung angeben, z.

regress=> SELECT * FROM compute_all_pair_by_craig(100) theresult(a integer, b integer);

Aber es ist viel besser zu nutzen RETURNS TABLEoder OUTParameter. Mit der früheren Syntax wäre Ihre Funktion:

create or replace function compute_all_pair_by_craig(id_obj bigint)
    returns table(a integer, b integer) as $$
begin
    return query select o.id, generate_series(0,o.value) from m_obj as o;     
end;
$$ language plpgsql;

Dies kann im SELECT-Listenkontext aufgerufen werden und kann verwendet werden, ohne explizit einen Typ zu erstellen oder die Ergebnisstruktur am Aufrufstandort anzugeben.


In der zweiten Hälfte der Frage werden im ersten Fall zwei separate Spalten in einer SELECT-Liste angegeben, während in der zweiten ein einzelner Verbund zurückgegeben wird. Es hängt eigentlich nicht damit zusammen, wie Sie das Ergebnis zurückgeben, sondern wie Sie die Funktion aufrufen. Wenn wir die Beispielfunktion erstellen:

CREATE OR REPLACE FUNCTION twocols() RETURNS TABLE(a integer, b integer) 
AS $$ SELECT x, x FROM generate_series(1,5) x; $$ LANGUAGE sql;

Sie werden den Unterschied zwischen den beiden Möglichkeiten zum Aufrufen einer Set-Return-Funktion sehen - in der SELECTListe eine PostgreSQL-spezifische Nicht-Standard-Erweiterung mit eigenartigem Verhalten:

regress=> SELECT twocols();
 twocols 
---------
 (1,1)
 (2,2)
 (3,3)
 (4,4)
 (5,5)
(5 rows)

oder als Tabelle auf die üblichere Weise:

regress=> SELECT * FROM twocols();
 a | b 
---+---
 1 | 1
 2 | 2
 3 | 3
 4 | 4
 5 | 5
(5 rows)
Craig Ringer
quelle
Gerade getestet, funktioniert perfekt. Und ich mag diese Syntax mit returns table.
Stephane Rolland
@StephaneRolland Aktualisiert mit Erläuterung des letzten Teils der Frage.
Craig Ringer
Danke für die Unterstützung. Jetzt ist es viel viel klarer.
Stephane Rolland