PostgreSQL中的计算/计算/虚拟/派生列


113

PostgreSQL是否支持计算/计算列,例如MS SQL Server?我在文档中找不到任何内容,但是由于许多其他DBMS都包含此功能,所以我认为我可能会丢失一些内容。

例如:http : //msdn.microsoft.com/en-us/library/ms191250.aspx


使用横向子查询表达式(Postgres功能),您可以轻松地向每行添加更多列。
维克多

Answers:


139

最多不支持Postgres 11 生成的列 -这是SQL标准中定义的,并且由某些RDBMS(包括DB2,MySQL和Oracle)实现。也没有SQL Server 的类似“计算列”

STORED生成的列在Postgres 12中引入。琐碎的例子:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

db <> 在这里拨弄

VIRTUAL生成的列可能带有下一个迭代之一。(尚未在Postgres 13中)。

有关:


在那之前,你可以模拟VIRTUAL生成具有列函数使用属性符号tbl.col),其外观和工作方式就像一个虚拟的生成列。出于历史原因,Postgres中存在某种语法上的奇怪之处,并且恰好适合这种情况。这个相关的答案有代码示例

表达式(看起来像一列)未包含在中SELECT * FROM tbl。您始终必须明确列出它。

也可以通过匹配的表达式索引来支持-提供的功能是IMMUTABLE。喜欢:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

备择方案

或者,您可以使用来实现类似的功能,还可以VIEW选择与表达式索引结合使用。然后SELECT *可以包括生成的列。

STORED可以使用功能相同的方式使用触发器来实现“ Persisted”()计算列。

物化视图是一个紧密相关的概念,自Postgres 9.3开始实施
在早期版本中,可以手动管理MV。


取决于您一次加载的数据量。触发器会大大降低速度。可能要考虑更新。
sam yi

1
当从oracle迁移到postgres时,这些解决方案几乎没有用(在没有测试用例的情况下无需对代码库进行大量代码更改)。从迁移的角度来看,有什么解决方案吗?
happybuddha

@happybuddha:请问您的问题。评论不是地方。您可以始终链接到该问题以获取上下文(并在此处添加评论以引起我的注意并链接到相关问题)。
Erwin Brandstetter

4
该功能目前正在开发中:commitfest.postgresql.org/16/1443
r90t

1
@cryanbhu:取决于您的设置和要求的详细信息。您可能会问一个带有必要信息的新问题。
Erwin Brandstetter

32

是的你可以!! 该解决方案应该简单,安全且高效...

我是Postgresql的新手,但是看来您可以通过将expression index视图配对使用来创建计算列(该视图是可选的,但会使生活变得更轻松)。

假设我的计算为md5(some_string_field),则将索引创建为:

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

现在,任何作用于查询的查询MD5(some_string_field)都将使用索引,而不是从头开始计算索引。例如:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

您可以使用explain进行检查。

但是,此时您依赖表的用户确切地知道如何构造该列。为了使生活更轻松,您可以VIEW在原始表的增强版本上创建一个,将计算值添加为新列:

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

现在,所有使用的查询some_table_augmented都可以使用,some_string_field_md5而不必担心它的工作方式。它们只会获得良好的性能。该视图不会复制原始表中的任何数据,因此从内存角度和性能角度来说都是很好的选择。但是请注意,您不能只在源表中更新/插入视图,但是,如果您确实需要,我相信可以使用规则将插入和更新重定向到源表(在最后一点上我可能是错的,因为我从未亲自尝试过)。

编辑:看来,如果查询涉及竞争索引,则计划程序引擎有时可能根本不使用expression-index。该选择似乎取决于数据。


1
您能否解释一下或举一个例子if the query involves competing indices
dvtan

17

一种方法是使用触发器!

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

在更新或插入行之前触发触发器。它更改了我们要计算NEW记录的字段,然后返回该记录。


扳机何时触发?我执行了上面的操作,insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;然后返回了:1 2和4 8
happybuddha

2
尝试insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;two列的值将自动计算!
Elmer

8

PostgreSQL 12支持生成的列:

PostgreSQL 12 Beta 1发布了!

生成的列

PostgreSQL 12允许创建生成的列,并使用其他列的内容使用表达式来计算其值。此功能提供了存储的生成的列,这些列在插入和更新时计算并保存在磁盘上。仅当将列作为查询的一部分读取时才计算的虚拟生成列尚未实现。


生成的列

生成的列是特殊列,始终从其他列计算得出。因此,表的视图就是列。

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> fiddle演示



1

好吧,不确定这是否是您的意思,但Posgres通常支持“虚拟” ETL语法。我在表中创建了一个空列,然后需要根据行中的值通过计算的记录来填充它。

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. 我怀疑它是如此的虚拟,这不是您想要的。
  2. 显然,它不是动态的,您只需运行一次。但是没有任何障碍可以触发它。

0

我有一个有效的代码并使用“计算”​​一词,我不在PostgreSQL上运行,而在PADB上运行

这是它的用法

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;

PADB到底是什么?
Gherman

ParAccel Analytic Database很老但是很不错... en.wikipedia.org/wiki/ParAccel
Wired604 '19

但是,它与有关Postgres的问题有什么关系?当然,有很多支持计算列的数据库。
Gherman

抱歉,我没有花时间返回上下文。...PADB基于postgress!
Wired604

-6

具有Check约束的轻量级解决方案:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

6
这与计算列的概念有何关系?您愿意解释吗?
Erwin Brandstetter

4
同意,这没有直接关系。但是,当您只需要像那样做某事时,它可以代替一个简单的情况field as 1 persisted
cinereo

2
一个描述确实会很好。我认为这个答案是,如果可以使用default子句完成计算,则可以使用default和check约束来防止任何人更改值。
罗斯·布拉德伯里

@Ross Bradbury:同意,但这仅适用于插入。如果从属列已更新,将无法正常工作。
Stefan Steiger
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.