将常见查询存储为列?

ibr*_*ter 36 postgresql database-design view

使用PostgreSQL,我有很多查询,如下所示:

SELECT <col 1>, <col 2>
     , (SELECT sum(<col x>)
        FROM   <otherTable> 
        WHERE  <other table foreignkeyCol>=<this table keycol>) AS <col 3>
FROM   <tbl>
Run Code Online (Sandbox Code Playgroud)

鉴于子选择在每种情况下都是相同的,有没有办法将该子选择存储为表中的伪列?基本上,我希望能够从表A中选择一列,它是表B中与记录相关的特定列的总和.这可能吗?

Erw*_*ter 73

有没有办法将该子选项存储为表中的伪列?

一个VIEW已被告知就像是一个完全有效的解决方案.但还有另一种方式可以更贴近你的问题.可以编写一个函数,该表型为参数来模拟一个"计算字段""生成的列".

考虑这个测试用例,源自您的描述:

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);
Run Code Online (Sandbox Code Playgroud)

创建模拟的函数col3:

CREATE FUNCTION col3(tbl_a)
  RETURNS int8 AS
$func$
    SELECT sum(colx)
    FROM   tbl_b b
    WHERE  b.a_id = $1.a_id
$func$ LANGUAGE SQL STABLE;
Run Code Online (Sandbox Code Playgroud)

现在您可以查询:

SELECT a_id, col1, col2, tbl_a.col3
FROM   tbl_a;
Run Code Online (Sandbox Code Playgroud)

甚至:

SELECT *, a.col3 FROM tbl_a a;
Run Code Online (Sandbox Code Playgroud)

注意:我如何写tbl_a.col3/ a.col3,而不仅仅是col3.这很重要.

Oracle中"虚拟列"不同,不会自动包含在SELECT * FROM tbl_a.你可以使用一个VIEW.

为什么这样做?

引用表列的常用方法是使用属性表示法:

SELECT tbl_a.col1 FROM tbl_a;

调用函数的常用方法是使用函数表示法:

SELECT col3(tbl_a);

通常,最好遵循这些规范方式,这与SQL标准一致.

但是在PostgreSQL中,功能表示法和属性表示法是等价的.所以这些工作也是如此:

SELECT col1(tbl_a) FROM tbl_a;
SELECT tbl_a.col3;

更多关于手册中的内容.
你现在可能已经看到了这一点.这看起来像是要添加一个额外的表列,tbl_acol3()实际上是一个函数,它将当前行tbl_a(或其别名)作为行类型参数并计算一个值.

SELECT *, a.col3
FROM   tbl_a AS a;
Run Code Online (Sandbox Code Playgroud)

如果存在实际列,col3则它具有优先级,并且系统不会将该行tbl_a作为参数查找该名称的函数.

它的美妙之处在于:您可以添加或删除列,tbl_a最后一个查询将动态返回所有当前列,其中视图只返回创建时存在的列(早期绑定与后期绑定*).
当然,您必须先删除依赖函数,然后才能删除表.在对表进行更改时,您必须注意不要使函数无效.

  • 该函数应该真正标记为"STABLE"(意味着如果在执行单个查询期间多次使用相同的参数调用它将返回相同的值),而不是"IMMUTABLE"(意味着它将*总是*无论数据库内容或时间的流逝,都为相同的参数返回相同的值.这样做的一件事是阻止在索引中使用函数,这是你想要的,否则如果对tbl_b进行了更改,索引就会被破坏.如果你只使用作为参数传递的行中的值,那么`IMMUTABLE`就可以了. (8认同)