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?