Kesalahan: fungsi set_valued dipanggil dalam konteks yang tidak dapat menerima set. Tentang apa ini?

11

Saya menggunakan Postgresql 9.1, dengan ubuntu 12.04.

Terinspirasi oleh jawaban Craig untuk pertanyaan saya Penggabungan jenis setof atau merekam setof saya pikir saya akan pergi baik dengan menggunakan return query, setof recorddan generator seri ke dalam fungsi plpgsql ini:

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;

Selama eksekusi saya mendapatkan kesalahan:

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

Apa yang salah ? Bertentangan dengan Craig, saya memberi tahu fungsi untuk kembali setof record.

Saya dapat mencapai sesuatu yang berfungsi persis seperti Craig, yaitu dengan mendefinisikan suatu tipe create type pair_id_value as (idx bigint, value integer)dan membuat fungsi plpgsql saya mengembalikan sebuah setof of pair_id_valuealih - alih a setof record.

Tetapi bahkan dengan solusi yang berfungsi ini, saya masih tidak mengerti mengapa select id, generate_series(0,13)sendirian akan mengembalikan hasil dalam dua kolom ... dan sebaliknya memanggil fungsi (mengembalikan setof pair_id_value) dengan return query select id, generate_series(0,my_obj.value) from my_objakan mengembalikan hasil hanya dalam satu kolom yang bidangnya terlihat seperti ini "(123123,0)" "(123123,1)" "(123123,2)" (3 baris) yang merupakan tupel jelas.

Apakah ini kasus di mana tabel sementara harus / harus dibuat?

Stephane Rolland
sumber
Itu tidak bisa menjadi teks persis dari fungsi yang Anda jalankan karena tidak dikompilasi; ada titik koma berlebih setelah BEGINdan titik hilang setelah RETURN QUERY. Setelah memperbaiki kesalahan-kesalahan itu saya mengkonfirmasi kesalahan ketika kembali record; akan menjelaskan jawaban.
Craig Ringer
@CraigRinger Saya meletakkan kembali tanda koma di tempatnya.
Stephane Rolland

Jawaban:

7

Pesan kesalahan sangat tidak membantu:

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);

tetapi jika Anda mengulangi kueri untuk menyebutnya sebagai fungsi set-return yang tepat, Anda akan melihat masalah sebenarnya:

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);

Jika Anda menggunakan SETOF RECORDtanpa OUTdaftar parameter, Anda harus menentukan hasil dalam pernyataan panggilan, misalnya:

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

Namun, lebih baik menggunakan RETURNS TABLEatau OUTparameter. Dengan sintaks sebelumnya, fungsi Anda adalah:

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;

Ini bisa dipanggil dalam konteks daftar SELECT dan dapat digunakan tanpa membuat tipe secara eksplisit atau menentukan struktur hasil di situs panggilan.


Adapun bagian kedua dari pertanyaan, apa yang terjadi adalah bahwa kasus pertama menentukan dua kolom terpisah dalam daftar SELECT, sedangkan yang kedua mengembalikan komposit tunggal. Ini sebenarnya tidak ada hubungannya dengan bagaimana Anda mengembalikan hasilnya, tetapi bagaimana Anda menjalankan fungsi. Jika kita membuat fungsi sampel:

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

Anda akan melihat perbedaan dalam dua cara untuk memanggil fungsi set-return - dalam SELECTdaftar, ekstensi non-standar spesifik PostgreSQL dengan perilaku unik:

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

atau sebagai tabel dengan cara yang lebih standar:

regress=> SELECT * FROM twocols();
 a | b 
---+---
 1 | 1
 2 | 2
 3 | 3
 4 | 4
 5 | 5
(5 rows)
Craig Ringer
sumber
Baru diuji, berfungsi sempurna. Dan saya suka sintaks ini dengan returns table.
Stephane Rolland
@StephaneRolland Diperbarui dengan penjelasan bagian terakhir dari pertanyaan juga.
Craig Ringer
Terima kasih atas dukungannya. Sekarang jauh lebih jelas.
Stephane Rolland