我正在尝试执行一些在函数内使用的SELECT,我的代码是这样的:
DECLARE
result_one record;
BEGIN
EXECUTE 'WITH Q1 AS
(
SELECT id
FROM table_two
INNER JOINs, WHERE, etc, ORDER BY... DESC
)
SELECT Q1.id
FROM Q1
WHERE, ORDER BY...DESC';
RETURN final_result;
END;
我知道如何在MySQL中做到这一点,但是在PostgreSQL中却失败了。我应该更改什么或应该怎么做?
答案 0 :(得分:1)
要使一个函数能够返回多行,必须将其声明为returns table()
(或returns setof
)
要真正从PL / pgSQL函数中返回结果,您需要使用return query
(作为documented in the manual)
要在Postgres中构建动态SQL,强烈建议使用format()
函数正确处理标识符(并使源代码更易于阅读)。
所以您需要类似的东西:
create or replace function get_data(p_sort_column text)
returns table (id integer)
as
$$
begin
return query execute
format(
'with q1 as (
select id
from table_two
join table_three on ...
)
select q1.id
from q1
order by %I desc', p_sort_column);
end;
$$
language plpgsql;
请注意,除非您在查询中使用order by
或LIMIT
,否则在对最终查询进行排序时,CTE中的distinct on ()
几乎没有用。
如果对动态SQL使用另一种美元报价,则可以使您的生活更加轻松:
create or replace function get_data(p_sort_column text)
returns table (id integer)
as
$$
begin
return query execute
format(
$query$
with q1 as (
select id
from table_two
join table_three on ...
)
select q1.id
from q1
order by %I desc
$query$, p_sort_column);
end;
$$
language plpgsql;
答案 1 :(得分:0)
加,要为ORDER BY
动态选择一列,您必须将该列添加到CTE的SELECT
列表中,如果该列可以被复制(就像传递'id'一样)...
更好的是,完全删除CTE 。您的问题中没有任何内容可以保证它的使用。 (仅在Postgres中需要 时使用CTE,它们通常比等效的子查询或简单查询慢。)
CREATE OR REPLACE FUNCTION get_data(p_sort_column text)
RETURNS TABLE (id integer) AS
$func$
BEGIN
RETURN QUERY EXECUTE format(
$q$
SELECT t2.id -- assuming you meant t2?
FROM table_two t2
JOIN table_three t3 on ...
ORDER BY t2.%I DESC NULL LAST -- see below!
$q$, $1);
END
$func$ LANGUAGE plpgsql;
我附加了NULLS LAST
-您可能也想要这么做:
如果p_sort_column
始终来自同一张表,请在ORDER BY
子句中硬编码该表名/别名。否则,分别传递表名/别名 并自动对其自动引用以确保安全:
我建议在具有多个联接(t2.id
而不仅仅是id
)的更大查询中对所有列名进行表限定。避免各种令人惊讶的结果/混乱/滥用。
您可能需要对表名(myschema.table_two
进行模式限定,以避免在使用其他search_path
调用函数时遇到类似的麻烦: