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

2skhul33  于 2022-11-23  发布在  PostgreSQL
关注(0)|答案(8)|浏览(215)

PostgreSQL是否支持计算/计算列,就像MS SQL Server一样?我在文档中找不到任何东西,但由于许多其他DBMS都包含此功能,我想我可能遗漏了一些东西。
例如:http://msdn.microsoft.com/en-us/library/ms191250.aspx

guz6ccqo

guz6ccqo1#

Postgres 12或更高版本

**STORED generated columns**是随Postgres 12引入的-如SQL标准中所定义,并由一些RDBMS(包括DB2、MySQL和Oracle)实现。或SQL Server的类似 “计算列”

举个小例子:

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

fiddle
VIRTUAL生成的列可能会在下一次迭代中出现。(Postgres 15中还没有)。
相关:

  • 函数调用的属性表示法出错

Postgres 11或更高版本

最多不支持Postgres 11“生成的列”。
你可以用一个函数来模拟VIRTUAL生成的列,使用 * 属性表示法 *(tbl.col),看起来和工作起来都很像虚拟生成的列。这是一个语法上的古怪之处,在Postgres中是因为历史原因而存在的,碰巧适合这种情况。这个相关的答案有代码示例**:

  • 是否将常用查询存储为列?

但是,SELECT * FROM tbl中不包含表达式(看起来像一个列)。您必须始终显式列出它。
如果函数是IMMUTABLE,也可以使用匹配的expression index来支持。例如:

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

备选方案

或者,您可以使用VIEW实现类似的功能,并可以选择性地与表达式索引结合。然后SELECT *可以包含生成的列。
“持久化”(STORED)计算列可以用triggers以功能等效的方式实现。
X1 E5 F1 X是一个相关概念,X1 E6 F1 X。
在早期版本中,用户可以手动管理MV。

0lvr5msh

0lvr5msh2#

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

我是postgresql的新手,但似乎可以通过使用expression indexview(视图是可选的,但使工作变得更容易)来创建计算列。
假设我的计算是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,而不用担心它的工作原理。它们只是获得了很好的性能。视图不会从原始表复制任何数据,因此它在内存方面和性能方面都很好。但是请注意,您不能更新/插入到视图中,只能更新/插入到源表中,但如果您确实需要,我相信您可以使用rules将插入和更新重定向到源表(最后一点我可能是错的,因为我自己从来没有尝试过)。

  • 编辑:* 如果查询涉及竞争索引,计划引擎有时可能根本不使用表达式索引。选择似乎与数据相关。
vof42yt1

vof42yt13#

一种方法是使用触发器!

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记录的字段,然后返回该记录。

lmyy7pcs

lmyy7pcs4#

PostgreSQL 12支持生成的列:
PostgreSQL 12 Beta 1 Released!

生成的列

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

Generated Columns
生成的列是一种特殊的列,它始终是从其它列计算出来的。因此,对于列而言,视图就像对于表而言一样。

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

46qrfjad

46qrfjad5#

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

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/

1.它是如此的愚蠢,我怀疑它不是你正在寻找的。
1.显然它不是动态的,你运行一次。但是没有障碍让它进入触发器。

moiiocjp

moiiocjp6#

创建空虚拟列的示例

,(SELECT *
  From (values (''))
  A("virtual_col"))

创建两个具有值的虚拟列的示例

SELECT *
From (values (45,'Completed')
    , (1,'In Progress')
    , (1,'Waiting')
    , (1,'Loading')
   ) A("Count","Status")
order by "Count" desc
lh80um4z

lh80um4z7#

我有一个工作的代码,并使用术语计算,我不是在postgresSQL纯tho我们运行在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    ;
vfh0ocws

vfh0ocws8#

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

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

相关问题