SQL 模拟生成的列未按预期工作的函数
SQL function to emulate a generated column not working as expected
我写了一个 SQL 函数,看起来像这样:
CREATE OR REPLACE FUNCTION bathrooms(structure)
RETURNS double precision AS
$BODY$
SELECT coalesce(bathrooms_total, 0) +
coalesce(bathrooms_full, 0) +
coalesce(bathrooms_half, 0)*.5 +
coalesce(bathrooms_three_quarter, 0)*.75
FROM structure
$BODY$
LANGUAGE sql VOLATILE;
并注意到在使用它时,我通常会得到错误的答案。 IE。它会告诉我一排有 5 个浴室,而实际上该排只有 1.5 个。所以我写了一个查询来测试看起来像这样的函数:
SELECT coalesce(bathrooms_total, 0) +
coalesce(bathrooms_full, 0) +
coalesce(bathrooms_half, 0)*.5 +
coalesce(bathrooms_three_quarter, 0)*.75,
bathrooms(structure)
FROM structure
这返回了一个非常有趣的结果:
row# real_bathrooms
func_bathrooms
1. 4 4
2. 2 4
3. 1 4
4. 1.75 4
5. 2.5 4
6. 1.5 4
7. 1.75 4
.
.
.
450. 2.5 4
451. 3.5 4
452. 1.5 1.5!!!!!!
453. 1 1.5
454. 2.75 1.5
.
.
该函数似乎计算了一次,然后将该值缓存了大约 450 行,然后重新计算。这在 900、1350 和 1800 等处继续。这开始有意义,除了我在 docs and on stack overflow 中阅读的所有内容让我认为将函数设置为 volatile 应该可以解决此类问题。然而,这个问题,就像陈旧的数据一样,仍然存在。 (对不起,我忍不住了。)
由于此处的评论请求是数据示例:
有什么想法吗?
我觉得你的问题不是你想的那样。这似乎不是缓存问题 - 而是看起来您每次发送给函数的每条记录都在查询 table 的内容。
我怀疑这可能是您对函数的意图。
CREATE OR REPLACE FUNCTION bathrooms(bath structure)
RETURNS double precision AS
$BODY$
BEGIN
return coalesce(bath.bathrooms_total, 0) +
coalesce(bath.bathrooms_full, 0) +
coalesce(bath.bathrooms_half, 0)*.5 +
coalesce(bath.bathrooms_three_quarter, 0)*.75;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
您的函数没有像您想象的那样引用传递的参数。 FROM structure
中的 structure
引用基础 table, 而不是 传递的参数。
您似乎想要的是一个模拟 "computed field" 或 "generated column" 的函数。会像这样工作:
CREATE OR REPLACE FUNCTION bathrooms(structure)
RETURNS double precision AS
$func$
SELECT coalesce(.bathrooms_total, 0)
+ coalesce(.bathrooms_full, 0)
+ coalesce(.bathrooms_half, 0) * .5
+ coalesce(.bathrooms_three_quarter, 0) * .75
$func$ LANGUAGE sql;
调用(示例):
SELECT *, pg_temp.bathrooms(s) FROM structure s;
详细解释:
- Store common query as column?
我写了一个 SQL 函数,看起来像这样:
CREATE OR REPLACE FUNCTION bathrooms(structure)
RETURNS double precision AS
$BODY$
SELECT coalesce(bathrooms_total, 0) +
coalesce(bathrooms_full, 0) +
coalesce(bathrooms_half, 0)*.5 +
coalesce(bathrooms_three_quarter, 0)*.75
FROM structure
$BODY$
LANGUAGE sql VOLATILE;
并注意到在使用它时,我通常会得到错误的答案。 IE。它会告诉我一排有 5 个浴室,而实际上该排只有 1.5 个。所以我写了一个查询来测试看起来像这样的函数:
SELECT coalesce(bathrooms_total, 0) +
coalesce(bathrooms_full, 0) +
coalesce(bathrooms_half, 0)*.5 +
coalesce(bathrooms_three_quarter, 0)*.75,
bathrooms(structure)
FROM structure
这返回了一个非常有趣的结果:
row# real_bathrooms
func_bathrooms
1. 4 4
2. 2 4
3. 1 4
4. 1.75 4
5. 2.5 4
6. 1.5 4
7. 1.75 4
.
.
.
450. 2.5 4
451. 3.5 4
452. 1.5 1.5!!!!!!
453. 1 1.5
454. 2.75 1.5
.
.
该函数似乎计算了一次,然后将该值缓存了大约 450 行,然后重新计算。这在 900、1350 和 1800 等处继续。这开始有意义,除了我在 docs and on stack overflow 中阅读的所有内容让我认为将函数设置为 volatile 应该可以解决此类问题。然而,这个问题,就像陈旧的数据一样,仍然存在。 (对不起,我忍不住了。)
由于此处的评论请求是数据示例:
有什么想法吗?
我觉得你的问题不是你想的那样。这似乎不是缓存问题 - 而是看起来您每次发送给函数的每条记录都在查询 table 的内容。
我怀疑这可能是您对函数的意图。
CREATE OR REPLACE FUNCTION bathrooms(bath structure)
RETURNS double precision AS
$BODY$
BEGIN
return coalesce(bath.bathrooms_total, 0) +
coalesce(bath.bathrooms_full, 0) +
coalesce(bath.bathrooms_half, 0)*.5 +
coalesce(bath.bathrooms_three_quarter, 0)*.75;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
您的函数没有像您想象的那样引用传递的参数。 FROM structure
中的 structure
引用基础 table, 而不是 传递的参数。
您似乎想要的是一个模拟 "computed field" 或 "generated column" 的函数。会像这样工作:
CREATE OR REPLACE FUNCTION bathrooms(structure)
RETURNS double precision AS
$func$
SELECT coalesce(.bathrooms_total, 0)
+ coalesce(.bathrooms_full, 0)
+ coalesce(.bathrooms_half, 0) * .5
+ coalesce(.bathrooms_three_quarter, 0) * .75
$func$ LANGUAGE sql;
调用(示例):
SELECT *, pg_temp.bathrooms(s) FROM structure s;
详细解释:
- Store common query as column?