我在下面的测试表上工作:
select * from test;
id | broker | affiliate | leads
----+---------+-----------+-------
1 | broker1 | aff1 | 1
2 | broker1 | aff2 | 2
3 | broker2 | aff2 | 4
(3 rows)
字符串
我想创建一个函数,它将接受group by
列名和where
predicate 。下面是该函数的工作示例:
DROP FUNCTION report2(TEXT,TEXT);
CREATE OR REPLACE FUNCTION report2(
group_by_column_name TEXT,
sql_where TEXT
)
RETURNS RECORD
AS $$
DECLARE
query TEXT;
result_row RECORD;
BEGIN
query := 'SELECT ';
IF group_by_column_name <> '' THEN
query := query || group_by_column_name || ', ';
END IF;
query := query || 'sum(leads) FROM test';
IF sql_where <> '' THEN
query := query || ' WHERE ' || sql_where;
END IF;
IF group_by_column_name <> '' THEN
query := query || ' GROUP BY(' || group_by_column_name || ')';
END IF;
RAISE NOTICE 'query: %;', query;
EXECUTE query INTO result_row;
RETURN result_row;
END
$$ LANGUAGE 'plpgsql';
型
它的用法:
select report2('broker', '');
NOTICE: query: SELECT broker, sum(leads) FROM test GROUP BY(broker);
report2
-------------
(broker1,3)
(1 row)
型
我不仅要获取查询的第一行,而且要获取所有行(显然)。
我尝试了以下方法:
DROP FUNCTION report2(TEXT,TEXT);
CREATE OR REPLACE FUNCTION report2(
group_by_column_name TEXT,
sql_where TEXT
)
RETURNS SETOF RECORD
AS $$
DECLARE
query TEXT;
result_row RECORD;
BEGIN
query := 'SELECT ';
IF group_by_column_name <> '' THEN
query := query || group_by_column_name || ', ';
END IF;
query := query || 'sum(leads) FROM test';
IF sql_where <> '' THEN
query := query || ' WHERE ' || sql_where;
END IF;
IF group_by_column_name <> '' THEN
query := query || ' GROUP BY(' || group_by_column_name || ')';
END IF;
RAISE NOTICE 'query: %;', query;
-- Does not worK:
-- FOR result_row IN EXECUTE query
-- LOOP
-- RETURN NEXT result_row;
-- END LOOP;
-- Does not worK:
-- RETURN QUERY EXECUTE query;
END
$$ LANGUAGE 'plpgsql';
型
在这两种情况下,对于FOR
或RETURN QUERY
,都会发生错误:
NOTICE: query: SELECT broker, sum(leads) FROM test GROUP BY(broker);
ERROR: materialize mode required, but it is not allowed in this context
CONTEXT: PL/pgSQL function report2(text,text) line 21 at RETURN NEXT
型
从[docs][1]:
If multiple rows are returned, only the first will be assigned to the INTO variable(s).
型
那么,如何才能获得全部结果呢?
[1]: https://(https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN)
型
2条答案
按热度按时间j2datikz1#
我会返回
setof json
而不是record
,因为结果行的数量不同,json
比record
更有用。所以函数如下:字符串
| 报告2|
| --|
| {“broker”:“broker1”,“sum”:3}|
| {“broker”:“broker 2”,“sum”:4}|
wz1wpwve2#
你在选择列表中使用了一个返回集合的函数。SRF的返回类型可能是明确指定的或可预测的,但你的记录集返回的怪物不符合条件。
从技术上讲,你提出的函数是完全正确的,精细和可用的-你可以 * 调用它,只是不是你尝试的方式。
字符串
| col1| col2|
| --|--|
| 经纪人1| 3 |
| 经纪人2| 4 |
你甚至可以让它把这些备份到记录中:
型
| 行|
| --|
| (broker 1,3)|
| (经纪人2,4)|
如果使用
row()
构造函数来防止解包,甚至可以将其构建到函数中:型
然后你可以公开地说它只返回 * 记录 ( 不关你的事 * 类型):
型
| R|
| --|
| (broker 1,3)|
| (经纪人2,4)|
我不知道你想做什么,为什么要这样做,但是多态类型可能会有帮助,如果你不介意 Package 和打开,来回转换和重新转换,把东西打包到
jsonb
suggestedStefanov.sm* 可能会更容易。如果你想json Package 结果,
jsonb
通过更好的索引提供了更高的性能,由于额外的functions and operators比常规的json
更灵活,加上jsonb
自动清理无关紧要的空白,排序和重复数据删除你的键,并且更紧凑地存储和传输。型
默认的
where true
条件在保存参数检查时会被优化掉。你不必检查group by列是否为null/empty -如果是,||
将使逗号和group by
文字无效。null||'something'
产生null
,并将其赋予format()
占位符%s
不会在那里放置任何东西。函数runs the same, just in less text。