postgresql - 在 Postgresql 8.4 中更改父表会破坏子表默认值

标签 postgresql

问题:在 Postgresql 中,如果表 temp_person_two 继承自 temp_person,则子表上的默认列值将被忽略(如果表)已更改。

如何复制:

首先,创建表和子表。子表应该有一列具有默认值。

CREATE TEMPORARY TABLE temp_person (
    person_id SERIAL,
    name      VARCHAR
);

CREATE TEMPORARY TABLE temp_person_two (
    has_default character varying(4) DEFAULT 'en'::character varying NOT NULL
) INHERITS (temp_person);

接下来,在父表上创建一个触发器,将其数据复制到子表(我知道这看起来像是糟糕的设计,但这是显示问题的最小测试用例)。

CREATE FUNCTION temp_person_insert() RETURNS trigger
LANGUAGE plpgsql
AS '
BEGIN
INSERT INTO temp_person_two VALUES ( NEW.* );
RETURN NULL;
END;
';

CREATE TRIGGER temp_person_insert_trigger
    BEFORE INSERT ON temp_person
    FOR EACH ROW
    EXECUTE PROCEDURE temp_person_insert();

然后将数据插入父级并从子级中选择数据。数据应该是正确的。

INSERT INTO temp_person (name) VALUES ('ovid');
SELECT * FROM temp_person_two;
 person_id | name | has_default
-----------+------+-------------
         1 | ovid | en
(1 row )

最后,通过添加新的不相关列来更改父表。尝试插入数据并观察发生“非空约束”违规:

ALTER TABLE temp_person ADD column foo text;
INSERT INTO temp_person(name) VALUES ('Corinna');
ERROR:  null value in column "has_default" violates not-null constraint
CONTEXT:  SQL statement "INSERT INTO temp_person_two VALUES (  $1 .* )"
PL/pgSQL function "temp_person_insert" line 2 at SQL statement

我的版本:

testing=# select version();
                                                version
-------------------------------------------------------------------------------------------------------
 PostgreSQL 8.4.17 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit
(1 row)

最佳答案

它一直存在到 9.3,但修复起来会很棘手,而且我不确定这是否只是不良行为而不是错误。

约束仍然存在,但看看列顺序。

                                  Table "pg_temp_2.temp_person"
  Column   |       Type        |                            Modifiers                            
-----------+-------------------+-----------------------------------------------------------------
 person_id | integer           | not null default nextval('temp_person_person_id_seq'::regclass)
 name      | character varying | 
Number of child tables: 1 (Use \d+ to list them.)

                                  Table "pg_temp_2.temp_person_two"
   Column    |         Type         |                            Modifiers                            
-------------+----------------------+-----------------------------------------------------------------
 person_id   | integer              | not null default nextval('temp_person_person_id_seq'::regclass)
 name        | character varying    | 
 has_default | character varying(4) | not null default 'en'::character varying
Inherits: temp_person

ALTER TABLE
                                  Table "pg_temp_2.temp_person_two"
   Column    |         Type         |                            Modifiers                            
-------------+----------------------+-----------------------------------------------------------------
 person_id   | integer              | not null default nextval('temp_person_person_id_seq'::regclass)
 name        | character varying    | 
 has_default | character varying(4) | not null default 'en'::character varying
 foo         | text                 | 
Inherits: temp_person

它在您的第一个示例中有效,因为您正在有效地执行以下操作:

INSERT INTO temp_person_two (person_id,name)
VALUES (person_id, name)

但是看看您的新列添加到子表中的位置 - 最后!所以你最终会得到

INSERT INTO temp_person_two (person_id,name,has_default)
VALUES (person_id, name, foo)

而不是你所希望的:

INSERT INTO temp_person_two (person_id,name,foo)...

那么 - 这里的正确行为是什么?如果 PostgreSQL 打乱子表中的列,可能会破坏代码。如果没有,也可能会破坏代码。事实上,我认为如果不进行大量 PG 代码更改,第一个选项是不可行的,因此从中期来看不太可能做到这一点。

故事的寓意:明确列出您的 INSERT 列名称。

手动可能需要一段时间。您知道任何带有正则表达式的语言吗? ;-)

关于postgresql - 在 Postgresql 8.4 中更改父表会破坏子表默认值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19227920/

相关文章:

postgresql - 在两个不同的go应用程序中来自postgres的数据查询不一致

java - 我需要在 Postgres 中格式化日期

ruby-on-rails - 如何将 ARRAY_TO_STRING 和 ARRAY_AGG 转换为 arel?

database - 为什么递归联合不适用于 PostgreSQL 中的复合类型

java - Spring Boot通过 JDBC 语句执行 DDL 删除架构时出错

postgresql - psycopg2.编程错误: syntax error

sql - 列复制和更新与列创建和插入

sql - 不跳行的Postgresql GROUP BY?

ruby-on-rails - ActiveRecord 和 Postgres 行锁定

json - 查询 Postgres 9.3 JSON 以检查数组是否包含字符串?