我遇到了一些我想要了解的奇怪行为。
我创建了一个plpgsql函数,除了ALTER TABLE ADD COLUMN之外什么都不做。我在同一张桌子上称它为2次:
SELECT
句SELECT
的SQL函数中结果不同:A)创建两列,而B)只创建一列。为什么呢?
代码:
CREATE FUNCTION add_text_column(table_name text, column_name text) RETURNS VOID
LANGUAGE plpgsql
AS $fff$
BEGIN
EXECUTE '
ALTER TABLE ' || table_name || '
ADD COLUMN ' || column_name || ' text;
';
END;
$fff$
;
-- this function is called only in B
CREATE FUNCTION add_many_text_columns(table_name text) RETURNS VOID
LANGUAGE SQL
AS $fff$
WITH
col_names (col_name) AS (
VALUES
( 'col_1' ),
( 'col_2' )
)
SELECT add_text_column(table_name, col_name)
FROM col_names
;
$fff$
;
-- A)
CREATE TABLE a (id integer);
WITH
col_names (col_name) AS (
VALUES
( 'col_1' ),
( 'col_2' )
)
SELECT add_text_column('a', col_name)
FROM col_names
;
SELECT * FROM a;
-- B)
CREATE TABLE b (id integer);
SELECT add_many_text_columns('b');
SELECT * FROM b;
结果:
CREATE FUNCTION
CREATE FUNCTION
CREATE TABLE
add_text_column
-----------------
(2 rows)
id | col_1 | col_2
----+-------+-------
(0 rows)
CREATE TABLE
add_many_text_columns
-----------------------
(1 row)
id | col_1
----+-------
(0 rows)
我正在使用PostgreSQL 10.4。请注意,这只是一个最小的工作示例,而不是我需要的全部功能。
答案 0 :(得分:2)
SELECT t(4)
当我运行g()
时,您认为会发生什么?从g called with 1
打印的唯一声明是add_many_text_columns
。
原因是你的SELECT
函数返回一个结果(void)。因为它是SQL而且只是返回CREATE OR REPLACE FUNCTION t(i INTEGER)
RETURNS SETOF VOID AS $$
SELECT g(id)
FROM generate_series(1, i) id;
$$ LANGUAGE SQL;
语句的结果,它似乎在获得第一个结果后停止执行,如果你想到它就有意义 - 它毕竟只能返回一个结果。
现在将功能更改为:
SELECT t(4)
再次运行g called with 1
g called with 2
g called with 3
g called with 4
,现在打印出来:
SETOF VOID
因为函数现在返回SETOF VOID
,所以它不会在第一个结果后停止并完全执行。
回到你的函数,你可以更改你的SQL函数以返回plpgsql
,但它确实没有多大意义 - 我想更好地将其更改为{{1并让它做PERFORM
:
CREATE OR REPLACE FUNCTION t(i INTEGER)
RETURNS VOID AS $$
BEGIN
PERFORM g(id)
FROM generate_series(1, i) id;
END
$$ LANGUAGE plpgsql;
这将完全执行该语句,它仍然返回一个VOID
。
答案 1 :(得分:1)
eurotrash provided a good explanation.
CREATE OR REPLACE FUNCTION t(i INTEGER)
RETURNS VOID AS
$func$
SELECT g(id)
FROM generate_series(1, i) id;
SELECT null::void;
$func$ LANGUAGE sql;
SQL函数执行任意SQL语句列表,返回 列表中最后一个查询的结果。在简单(非设定) case,将返回最后一个查询结果的第一行。
通过在末尾添加一个虚拟SELECT
,我们避免在处理具有多行的查询的第一行后停止Postgres。
CREATE OR REPLACE FUNCTION t(i INTEGER)
RETURNS VOID AS
$func$
SELECT count(g(id))
FROM generate_series(1, i) id;
$func$ LANGUAGE sql;
通过使用聚合函数,在任何情况下都会处理所有基础行。该函数返回bigint
(count()
返回的内容),因此我们得到行数。
如果您需要以某种未知原因返回void
,您可以投票:
CREATE OR REPLACE FUNCTION t(i INTEGER)
RETURNS VOID AS
$func$
SELECT count(g(id))::text::void
FROM generate_series(1, i) id;
$func$ LANGUAGE sql;
text
的演员阵容是踏脚石,因为bigint
到void
的演员阵容未定义。