以下代码按预期工作,返回两列数据(行号和有效值):
sql_amounts := '
SELECT
row_number() OVER (ORDER BY taken)::integer,
avg( amount )::double precision
FROM
x_function( '|| id || ', 25 ) ca,
x_table m
WHERE
m.category_id = 1 AND
m.location_id = ca.id AND
extract( month from m.taken ) = 1 AND
extract( day from m.taken ) = 1
GROUP BY
m.taken
ORDER BY
m.taken';
FOR r, amount IN EXECUTE sql_amounts LOOP
SELECT array_append( v_row, r::integer ) INTO v_row;
SELECT array_append( v_amount, amount::double precision ) INTO v_amount;
END LOOP;
以下代码无法按预期工作;第一列是行号,第二列是NULL
。
FOR r, amount IN
SELECT
row_number() OVER (ORDER BY taken)::integer,
avg( amount )::double precision
FROM
x_function( id, 25 ) ca,
x_table m
WHERE
m.category_id = 1 AND
m.location_id = ca.id AND
extract( month from m.taken ) = 1 AND
extract( day from m.taken ) = 1
GROUP BY
m.taken
ORDER BY
m.taken
LOOP
SELECT array_append( v_row, r::integer ) INTO v_row;
SELECT array_append( v_amount, amount::double precision ) INTO v_amount;
END LOOP;
当查询本身返回两个有效列时,为什么非工作代码会为第二列返回NULL
值? (这个问题主要是学术性的;如果有一种表达查询的方法而不需要将其包装在文本字符串中,那就太棒了。)
PostgreSQL 8.4
谢谢。
答案 0 :(得分:1)
这两个陈述并不完全等同。
假设id = 4,第一个计划/准备好每次通过,行为如下:
prepare dyn_stmt as '... x_function( 4, 25 ) ...'; execute dyn_stmt;
另一个只在第一次通过时计划/准备,并且表现得更像:
prepare stc_stmt as '... x_function( $1, 25 ) ...'; execute stc_stmt(4);
(循环实际上会让它为上面的方法准备一个光标,但除了这一点之外,我们还是这样。)
许多因素可能会使两者产生不同的结果。
x_table
指向不同的东西。将此视为这些副作用的例证:
deallocate all;
begin;
prepare good as select now();
prepare bad as select current_timestamp;
execute good; -- yields the current timestamp
execute bad; -- yields the current timestamp
commit;
execute good; -- yields the current timestamp
execute bad; -- yields the timestamp at which it was prepared
为什么两者在你的情况下没有返回相同的结果将取决于上下文(你只发布了你的pl / pgsql函数的一部分,所以很难说),但我的猜测是你遇到了上述问题的变异。
答案 1 :(得分:1)
来自Tom Lane:
我认为问题在于你假设“amount”将引用查询的表列,而实际上它是plpgsql函数的局部变量。除非您使用表的名称/别名限定列引用,否则第二种解释将优先。
注意:如果此类型存在歧义,PG 9.0将默认抛出错误。