sql - 为什么在PostgreSQL中创建生成的列时出现错误?

标签 sql postgresql database-design string-concatenation calculated-columns

CREATE TABLE my_app.person
(
    person_id smallserial NOT NULL,
    first_name character varying(50),
    last_name character varying(50),
    full_name character varying(100) generated always as (concat(first_name, ' ', last_name)) STORED,
    birth_date date,
    created_timestamp timestamp default current_timestamp,
    PRIMARY KEY (person_id)
);

错误:生成表达式不是一成不变的

目的是填充名字,最后填充到全名列中。

最佳答案

concat()不是IMMUTABLE(仅STABLE),因为它可以调用依赖于语言环境设置的数据类型输出函数(例如timestamptz_out)。 Tom Lane (core developer) explains it here.

并且first_name || ' ' || last_name等于,而不是等效于concat(first_name, ' ', last_name),而至少一列可以是NULL

详细说明:

  • Combine two columns and add into one new column

  • 解决方案

    要使其正常工作,请按照您演示的方式进行:
    CREATE TABLE person (
      person_id smallserial PRIMARY KEY
    , first_name varchar(50)
    , last_name  varchar(50)
    , full_name  varchar(101) GENERATED ALWAYS AS
                             (CASE WHEN first_name IS NULL THEN last_name
                                   WHEN last_name  IS NULL THEN first_name
                                   ELSE first_name || ' ' || last_name END) STORED
    , ...
    );
    

    db <> fiddle here
    CASE表达式的速度与所获得的一样快-远快于多个串联和函数调用。完全正确。

    ,如果您知道自己在做什么,并具有必要的特权,则创建一个IMMUTABLE concat函数,如此处所示(替换CASE表达式):
  • Create an immutable clone of concat_ws

  • 另外:full_name必须为varchar(101)(50 + 50 + 1)才有意义。或仅使用text列即可。看:
  • Any downsides of using data type "text" for storing strings?

  • 一般建议

    最佳解决方案取决于您计划如何精确地处理NULL值(和空字符串)。我可能不会添加生成的列,这通常比在运行时串联全名通常更昂贵且总体上容易出错。考虑一个 View 。或封装了精确串联逻辑的函数。

    有关的:
  • Computed / calculated / virtual / derived columns in PostgreSQL
  • Store common query as column?
  • 关于sql - 为什么在PostgreSQL中创建生成的列时出现错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60249404/

    相关文章:

    sql - delphi 中存储过程的返回值始终为空

    mysql - 仅当用户存在两种方式关系时才选择sql

    mysql - 谁能帮我写sql语句?

    mysql:选择所有被通知的人

    sql - 如何在Elasticsearch中发出请求?

    postgresql - Hibernate 和 PostgreSQL : REPEATABLE_READ and use of @Version annotation to avoid write skews and other phenomena

    sql - 使用 CTE 对查询结果进行分组

    java - Java 中的 Itree 数据类型

    mysql - MySql中如何正确处理长键约束(超过3072)?

    sql - 如何在 SQLITE3 中创建一对多?