Примечание: это вопрос, который является продолжением этого решения . Вам нужно прочитать ссылку, чтобы получить контекст для этого вопроса. Также это для postgres v9.4
Если мы хотим вернуть несколько столбцов, а не только 1 столбец, как мы можем достичь этого?
Давайте возьмем таблицу t:
create table t(tag_id int, tag text unique);
Теперь вот что я хочу:
всякий раз, когда я вызываю метод f_tag_id, я хочу, чтобы он возвращал все столбцы для уникальной строки, если она существует в таблице t
, иначе вставьте ее и верните все столбцы.
Так вот, что я пытался для f_insert_tag
Option1:
CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text)
RETURNS TABLE(_tag_p_id int, _tag_ text)
AS
$func$
BEGIN
INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
return query Select * from t where t.tag_id = tag_p_id;
EXCEPTION WHEN UNIQUE_VIOLATION THEN -- catch exception, NULL is returned
END
$func$ LANGUAGE plpgsql;
Вариант 2:
CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text, out _tag_id int, out _tag_ text)
AS
$func$
BEGIN
INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
Select t.tag_id, t.tag from t where t.tag_id = tag_p_id into _tag_id, _tag_;
EXCEPTION WHEN UNIQUE_VIOLATION THEN -- catch exception, NULL is returned
END
$func$ LANGUAGE plpgsql;
Вариант 3:
CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text)
returns setof t AS
$func$
BEGIN
INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
return query Select * from t where t.tag_id = tag_p_id;
EXCEPTION WHEN UNIQUE_VIOLATION THEN -- catch exception, NULL is returned
END
$func$ LANGUAGE plpgsql;
Все 3 работали сами по себе:
select f_insert_tag(1322, 'helloworldaa');
f_insert_tag
---------------------
(1322,helloworldaa)
Для другой функции, f_tag_id, я перепробовал много методов:
Вариант 1:
CREATE OR REPLACE FUNCTION f_tag_id(tag_p_id int, _tag text, out _tag_id int, out _tag_ text)
AS
$func$
BEGIN
LOOP
SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
UNION ALL
SELECT f_insert_tag(tag_p_id, _tag)
into _tag_id, _tag_;
EXIT WHEN _tag_id IS NOT NULL; -- else keep looping
END LOOP;
END
$func$ LANGUAGE plpgsql;
Вариант 2:
CREATE OR REPLACE FUNCTION f_tag_id(tag_p_id int, _tag text)
RETURNS table(_tag_id int, _tag_ text) AS
$func$
BEGIN
LOOP
SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
UNION ALL
SELECT f_insert_tag(tag_p_id, _tag)
into _tag_id, _tag_;
EXIT WHEN _tag_id IS NOT NULL; -- else keep looping
END LOOP;
END
$func$ LANGUAGE plpgsql;
Для обоих я получил одну и ту же ошибку:
select f_tag_id(22, 'test');
ERROR: each UNION query must have the same number of columns
LINE 3: SELECT f_insert_tag(tag_p_id, _tag)
^
QUERY: SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
UNION ALL
SELECT f_insert_tag(tag_p_id, _tag)
CONTEXT: PL/pgSQL function f_tag_id(integer,text) line 5 at SQL statement