Lỗi: hàm set_valued được gọi trong ngữ cảnh không thể chấp nhận một tập hợp. Nó là về cái gì?


11

Tôi sử dụng Postgresql 9.1, với Ubuntu 12.04.

Lấy cảm hứng từ câu trả lời của Craig cho câu hỏi của tôi Concatenation loại setof hoặc hồ sơ setof Tôi nghĩ tôi sẽ suôn sẻ với việc sử dụng return query, setof recordvà một máy phát điện hàng loạt vào chức năng plpgsql này:

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;

Trong quá trình thực thi tôi gặp lỗi:

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

Chuyện gì thế ? Trái với Craig tôi bảo hàm trả về setof record.

Tôi có thể đạt được một cái gì đó hoạt động chính xác như Craig, tức là bằng cách xác định một loại create type pair_id_value as (idx bigint, value integer)và hàm plpgsql của tôi trả về setof of pair_id_valuethay vì a setof record.

Nhưng ngay cả với giải pháp làm việc này, tôi vẫn không hiểu tại sao select id, generate_series(0,13)một mình sẽ trả về một kết quả trong hai cột ... và ngược lại gọi hàm (trả về setof cặp_id_value) return query select id, generate_series(0,my_obj.value) from my_objsẽ trả về kết quả chỉ trong một cột có trường trông như thế nào this "(123123,0)" "(123123,1)" "(123123,2)" (3 hàng) rõ ràng là bộ dữ liệu.

Đây có phải là trường hợp một bảng tạm thời phải / nên được tạo không?


Đó không thể là văn bản chính xác của chức năng bạn đang chạy vì nó không biên dịch; có một dấu chấm phẩy thừa sau BEGINvà thiếu một dấu sau RETURN QUERY. Sau khi sửa những lỗi đó tôi xác nhận lỗi khi quay lại record; sẽ giải thích trong câu trả lời.
Craig Ringer

@CraigRinger Tôi đặt dấu chấm phẩy trở lại.
Stephane Rolland

Câu trả lời:


7

Thông báo lỗi không hữu ích lắm:

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

nhưng nếu bạn viết lại truy vấn để gọi nó là hàm trả về tập hợp thích hợp, bạn sẽ thấy vấn đề thực sự:

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

Nếu bạn đang sử dụng SETOF RECORDmà không có OUTdanh sách tham số, bạn phải chỉ định kết quả trong câu lệnh gọi, ví dụ:

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

Tuy nhiên, tốt hơn nhiều là sử dụng RETURNS TABLEhoặc OUTtham số. Với cú pháp trước đây, chức năng của bạn sẽ là:

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;

Điều này có thể gọi được trong ngữ cảnh danh sách CHỌN và có thể được sử dụng mà không cần tạo một kiểu rõ ràng hoặc chỉ định cấu trúc kết quả tại trang web cuộc gọi.


Đối với nửa sau của câu hỏi, điều xảy ra là trường hợp thứ nhất chỉ định hai cột riêng biệt trong danh sách CHỌN, trong đó câu thứ hai trả về một hỗn hợp đơn. Nó thực sự không liên quan đến cách bạn trả về kết quả, mà là cách bạn gọi hàm. Nếu chúng ta tạo hàm mẫu:

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

Bạn sẽ thấy sự khác biệt trong hai cách để gọi hàm trả về tập hợp - trong SELECTdanh sách, tiện ích mở rộng không chuẩn cụ thể của PostgreQuery với hành vi kỳ quặc:

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

hoặc dưới dạng bảng theo cách chuẩn hơn:

regress=> SELECT * FROM twocols();
 a | b 
---+---
 1 | 1
 2 | 2
 3 | 3
 4 | 4
 5 | 5
(5 rows)

Chỉ cần thử nghiệm, hoạt động hoàn hảo. Và tôi thích cú pháp này với returns table.
Stephane Rolland

@StephaneRolland Cập nhật với phần giải thích phần sau của câu hỏi.
Craig Ringer

thx cho sự hỗ trợ. Bây giờ thì rõ ràng hơn nhiều.
Stephane Rolland
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.