【问题标题】:Computed / calculated / virtual / derived columns in PostgreSQLPostgreSQL 中的计算/计算/虚拟/派生列
【发布时间】:2012-01-05 05:29:52
【问题描述】:

PostgreSQL 是否支持计算/计算列,例如 MS SQL Server?我在文档中找不到任何内容,但由于此功能包含在许多其他 DBMS 中,我想我可能会遗漏一些东西。

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

【问题讨论】:

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

标签: sql postgresql generated-columns


【解决方案1】:

最多不支持 Postgres 11 生成的列 - 如 SQL 标准中所定义并由包括 DB2、MySQL 和 Oracle 在内的一些 RDBMS 实现。也不是 SQL Server 的类似“计算列”

STORED 生成的列由 Postgres 12 引入。简单的例子:

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

db小提琴here

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

相关:


在此之前,您可以使用 属性表示法 (tbl.col) 模拟具有 函数VIRTUAL 生成的列,该 看起来和工作起来很像一个虚拟生成的列。由于历史原因,这在 Postgres 中存在一些语法上的奇怪之处,并且恰好适合这种情况。这个相关的答案有代码示例

不过,SELECT * FROM tbl 中不包含表达式(看起来像一列)。您总是必须明确列出它。

也可以通过匹配的expression index 来支持 - 只要函数是IMMUTABLE。喜欢:

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

替代品

或者,您可以使用VIEW 实现类似的功能,可选地与表达式索引结合使用。那么SELECT *可以包含生成的列。

“持久”(STORED) 计算列可以用triggers 以功能相同的方式实现。

Materialized views 是一个密切相关的概念,implemented since Postgres 9.3
在早期版本中,可以手动管理 MV。

【讨论】:

  • 取决于您一次加载的数据量.. 触发器可以大大减慢速度。可能需要考虑更新。
  • 在从 oracle 迁移到 postgres 时,这些解决方案几乎毫无用处(无需对没有测试用例的代码库进行大量代码更改)。从迁移的角度有什么解决方案吗?
  • @happybuddha:请将您的问题作为问题提出。评论不是地方。您可以随时链接到此问题的上下文(并在此处添加评论以引起我的注意并链接到相关问题)。
  • 该功能正在开发中:commitfest.postgresql.org/16/1443
  • @cryanbhu:取决于您的设置和要求的详细信息。您可能会问一个包含必要信息的新问题。
【解决方案2】:

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

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

【讨论】:

  • 这与计算列的概念有什么关系?你愿意解释一下吗?
  • 同意,没有直接关系。但是,当您只需要执行 field as 1 persisted 之类的操作时,它可以替代简单的情况。
  • 描述确实很好。我认为这个答案是,如果可以使用默认子句完成计算,那么您可以使用默认值和检查约束来防止任何人更改值。
  • @Ross Bradbury:同意,但这仅适用于插入。如果从属列被更新,它将不起作用。
【解决方案3】:

一种方法是使用触发器!

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 and 4 8
  • 试试insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;two列的值会自动计算出来!
【解决方案4】:

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

我是 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 将插入和更新重定向到源表(我最后可能是错的指出我自己从未尝试过)。

编辑:如果查询涉及竞争索引,规划引擎有时可能根本不使用表达式索引。选择似乎取决于数据。

【讨论】:

  • 你能解释一下if the query involves competing indices的例子吗?
【解决方案5】:

我有一个有效的代码并使用计算的术语,我不在 postgresSQL 上,我们在 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?
  • ParAccel 分析数据库虽然老旧但不错...en.wikipedia.org/wiki/ParAccel
  • 但是它与 Postgres 的问题有什么关系呢?当然有很多数据库都支持计算列。
  • 啊抱歉,我没有花时间回到上下文中……PADB 是基于 postgress 的!
【解决方案6】:

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

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. 太假了,我怀疑这不是您要找的。​​li>
  2. 显然它不是动态的,你运行一次。但让它进入触发器没有障碍。

【讨论】:

    【解决方案7】:

    PostgreSQL 12 支持生成列:

    PostgreSQL 12 Beta 1 Released!

    生成的列

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


    Generated Columns

    生成的列是始终从其他列计算的特殊列。因此,对于列,视图对于表是什么。

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

    db<>fiddle demo

    猜你喜欢
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多