有没有一种方法可以将子查询作为伪列存储在表中?
像
VIEW
这样的解决方案是完全有效的。请尝试。
但是还有一种更贴近您问题的方式:计算字段或生成列。Postgres 11引入了STORED生成列。详情请见:
在PostgreSQL中计算/计算/虚拟/派生列
对于旧版本,或者如果您喜欢VIRTUAL生成列(尚未实现,直到Postgres 15),则可以使用以表类型为参数的函数模拟该功能。
考虑以下测试用例,源自您的描述:
CREATE TABLE tbl_a (a_id int, col1 int, col2 int);
INSERT INTO tbl_a VALUES (1,1,1), (2,2,2), (3,3,3), (4,4,4);
CREATE TABLE tbl_b (b_id int, a_id int, colx int);
INSERT INTO tbl_b VALUES
(1,1,5), (2,1,5), (3,1,1)
, (4,2,8), (5,2,8), (6,2,6)
, (7,3,11), (8,3,11), (9,3,11);
创建一个函数来模拟
col3
:
CREATE FUNCTION col3(tbl_a)
RETURNS int8
LANGUAGE sql STABLE AS
$func$
SELECT sum(colx)
FROM tbl_b b
WHERE b.a_id = $1.a_id
$func$;
现在您可以查询:
SELECT a_id, col1, col2, tbl_a.col3
FROM tbl_a;
或者甚至:
SELECT *, a.col3 FROM tbl_a a;
请注意,我写的是
tbl_a.col3
/
a.col3
,而不仅仅是
col3
。这是
必要的。
与Oracle中的
"虚拟列"不同,它不会自动包含在
SELECT * FROM tbl_a
中。你可以使用一个
VIEW
来实现。
为什么这样做有效?
通常引用表列的方法是使用
属性表示法:
SELECT tbl_a.col1 FROM tbl_a;
调用函数的常见方式是使用
函数表示法:
SELECT col3(tbl_a);
一般来说,最好
坚持这些规范的方式,这与SQL标准相符。
但是Postgres也允许属性表示法。这些也可以工作:
SELECT col1(tbl_a) FROM tbl_a;
SELECT tbl_a.col3;
在手册中可以找到更多相关信息。
你现在可能已经看出来了,这个看起来像是你要在表tbl_a
中添加一列,而col3()
实际上是一个函数,它以tbl_a
(或其别名)的当前行作为行类型参数,并计算一个值。
SELECT *, a.col3
FROM tbl_a AS a;
如果存在实际列
col3
,它优先级最高,系统不会寻找以行
tbl_a
为参数的该名称函数。
"美妙"之处在于:您可以添加或删除来自
tbl_a
的列,并且最后一个查询将动态返回所有当前列,而视图仅返回创建时存在的列(早期绑定与
*
的后期绑定)。
当然,现在您必须放弃依赖的函数才能删除表。并且在对表进行更改时要注意不使函数失效。
我仍然不会使用它。对于无辜的读者来说太令人惊讶了。