Помилка: функція set_valued викликається в контексті, який не може прийняти набір. Про що це?


11

Я використовую Postgresql 9.1, з ubuntu 12.04.

Натхненний відповідь Крейга на моє запитання конкатенацію setof типу або setof записи , я думав , я б добре з використанням return query, setof recordі генератор серії в цій функцію plpgsql:

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;

Під час виконання я отримую помилку:

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

Що не так ? На відміну від Крейга, я кажу функції повернутися setof record.

Я можу домогтися чогось, що працює точно так само, як Craig, тобто, визначивши тип create type pair_id_value as (idx bigint, value integer)і моя функція plpgsql повертає setof of pair_id_valueзамість a setof record.

Але навіть маючи це робоче рішення, я все ще не розумію, чому select id, generate_series(0,13)один поверне результат у двох стовпцях ... і навпаки, виклик функції (повертає setof pair_id_value) з return query select id, generate_series(0,my_obj.value) from my_objповерне результат лише в одному стовпчику, яке поле виглядає це "(123123,0)" "(123123,1)" "(123123,2)" (3 ряди), які очевидно є кортежами.

Чи це випадок, коли необхідно / слід створити тимчасову таблицю?


Це не може бути точним текстом функції, яку ви виконуєте, оскільки вона не компілюється; є зайва крапка з комою після BEGINта відсутність після RETURN QUERY. Після виправлення цих помилок я підтверджую помилку при поверненні record; пояснимо у відповідь.
Крейг Рінгер

@CraigRinger Я повертаю крапку з комою на місце.
Стефан Ролланд

Відповіді:


7

Повідомлення про помилку не дуже корисне:

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

але якщо перефразовувати запит, щоб викликати його як належну функцію повернення набору, ви побачите справжню проблему:

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

Якщо ви використовуєте SETOF RECORDбез OUTсписку параметрів, ви повинні вказати результати в операторі виклику, наприклад:

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

Однак набагато краще використовувати RETURNS TABLEабо OUTпараметри. З колишнім синтаксисом вашою функцією буде:

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;

Це можна викликати в контексті списку SELECT і може використовуватися без створення явного типу або вказівки структури результатів на сайті виклику.


Що стосується другої половини питання, то, що відбувається, це те, що 1-й випадок вказує два окремі стовпці у списку SELECT, коли другий повертає єдиний композит. Це насправді пов'язане не з тим, як ви повертаєте результат, а з тим, як ви викликаєте функцію. Якщо ми створимо вибіркову функцію:

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

Ви побачите різницю у двох способах викликати функцію повернення набору - у SELECTсписку, нестандартне розширення PostgreSQL з химерною поведінкою:

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

або як таблиця більш стандартним способом:

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

Просто перевірена, працює ідеально. І мені подобається цей синтаксис с returns table.
Стефан Ролланд

@StephaneRolland Оновлено з поясненням останньої частини питання теж.
Крейг Рінгер

THX для підтримки. Зараз це набагато зрозуміліше.
Стефан Ролланд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.