PostgreSQL:生成的列


16

PostgreSQL支持生成的列吗?也称为虚拟列。我不是在谈论IDENTITY专栏

我找不到有关此卓越功能的任何信息,但我知道它在SQL Server以及最新版本的MariaDB和MySQL中都可用。

SQL:2003标准中提到了该功能,并且在2006年左右的PostgreSQL论坛上进行了一些讨论,但是我对此没有实质性的了解。

关于SO有一些讨论,但是现在讨论已经很久了,所以它可能已经过时了。


2
2012年关于SO的这个相关答案可能会有所帮助:stackoverflow.com/questions/11165450/…仍然有效。
Erwin Brandstetter,2017年

@ErwinBrandstetter对不起,我错过了此评论。这是一个有用的技巧。谢谢。
芒果

Answers:


17

不确定这是否是您想要的,但是属性符号row.full_name和函数符号full_name(row)在postgresql中是等效的。

就是说你坐桌

CREATE TABLE people (
  first_name text,
  last_name text
);

和一个功能:

CREATE FUNCTION full_name(people) RETURNS text AS $$
  SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;

并这样称呼它:

select full_name from people

那是你需要的吗?

为了加快速度,您可以创建一个表达式索引:

CREATE INDEX people_full_name_idx ON people
USING GIN (to_tsvector('english', full_name(people)));

或将所有内容存储在实例化视图中。

从此处获取的示例:http : //bernardoamc.github.io/sql/2015/05/11/postgres-virtual-columns/


2
这是正确的答案。例如,请参见Postgrest如何将此行为称为“计算列”。
fiatjaf

错字,我认为-选择应该是select people.full_name from people还是select full_name(people) from people
Barguast

不,它像那样工作。可以像在常规SQL中一样省略“从人中选择人。全名”中的前缀。
Fabian Zeindl

我错过了这个答案,就在我放弃很久以后。谢谢你的建议。
芒果

1
那你能改变接受的答案吗?
Fabian Zeindl

6

不,目前不支持(自Postgres 9.6起)。

唯一的解决方法是使用触发器或视图(如果它是不需要索引的简单计算)。


老鼠 我想如果我需要表演的话可以去物化。我已经添加了对该功能的要求,因为它已经在竞争中可用。
曼戈

1
无需MVIEW。具有触发器的列还将使您可以索引该列的内容
a_horse_with_no_name

我在存储其他实际列方面存在一个哲学问题,这些实际列基本上是其他数据的重复。它使表格不规范化。
曼戈

5
好吧,计算列就是这样:存储非规范化数据。计算列的值如何生成无关紧要。我看不到“实际”计算列与通过触发器生成的列之间的概念差异
a_horse_with_no_name

另一个解决方法(在某些情况下)是对表达式建立索引。
ypercubeᵀᴹ

5

是: GENERATED ALWAYS AS … STORED

SQL:2003标准中所述,Postgres 12添加了用于生成列的功能。

该值是在INSERT或时生成的UPDATE,然后像其他任何值一样与该行一起存储。

生成的对象必须基于同一表的基本列或不可变的函数

语法很简单,在上有一个子句CREATE TABLE

GENERATED ALWAYS AS ( generation_expr ) STORED 

例:

CREATE TABLE people (
    ...,
    height_cm NUMERIC,
    height_in NUMERIC GENERATED ALWAYS AS ( height_cm / 2.54 ) STORED
);

特征:

  • 可以索引。
  • SQL标准的一部分。

注意事项:

  • 基于同一表(非相关表)的列
  • 不允许分区(不能是分区键的一部分)
  • 数据总是写入行,占用存储空间
    • 将来的功能可能会为未存储的即时计算值提供虚拟
  • 单代深层(使用基本列,而不是另一个生成的列)
  • 没有GENERATED BY DEFAULT(您无法覆盖值)
  • 无法在触发之前访问gen-col(值尚未确定)
  • 函数必须是不可变的

看到:


感谢您提供的信息。我看到版本12尚未完全发布,但我很期待它。我注意到PostgreSQL使用更标准的语法,但与MSSQL相同。我在这里找到了SQL2003规范:sigmodrecord.org/publications/sigmodRecord/0403/…。我一直说SQL是一个非常缓慢的标准,而DBMS的实现甚至很慢。
曼戈

0

根据您的用例,您可以通过声明一个新列并在插入/更新时使用触发器填充它来实现这种行为。

如果可能的话,我将使用上述答案来避免复制可能从您已有的数据派生的数据,但这确实可以解决问题,并且对于想要一次计算并保存的计算密集型派生字段很有用。

我考虑了这种方法来解决一个问题,即有时我只有18位密钥中的15位(最后3位只是校验和),但希望能够执行外键关系。

触发器上的PG文档:https : //www.postgresql.org/docs/9.6/sql-createtrigger.html

W3示例:https//www.w3resource.com/PostgreSQL/postgresql-triggers.php

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.