【问题标题】:How to substitute a variable when creating a check constraint?创建检查约束时如何替换变量?
【发布时间】:2021-01-02 18:21:16
【问题描述】:

我需要为新添加的行添加必填字段。但是,由于表很大,不希望为旧行设置默认值。我需要提供一个自动脚本来执行此操作。 我试过了,但它不起作用:

do $$
declare 
    max_id int8;
begin
    select max(id) into max_id from transactions;
    alter table transactions add constraint check_process_is_assigned check (id <= max_id or process_id is not null);
end $$;

【问题讨论】:

  • id总是小于或等于max_id(假设不是null)。逻辑的意义何在?
  • @GordonLinoff 所说的以及来自docs 的补充:“目前,CHECK 表达式不能包含子查询,也不能引用当前行的列以外的变量(参见第 5.4.1 节)。系统列可以引用 tableoid,但不能引用任何其他系统列。"
  • @Gordon:AIUI 的重点是创建一个 CHECK 约束,该约束仅对 future 行(大于当前最大值的 ID)强制执行 process_id IS NOT NULL

标签: sql postgresql dynamic-sql check-constraints


【解决方案1】:

ALTER TABLE 等实用程序命令不接受参数。只有基本的 DML 命令 SELECTINSERTUPDATEDELETE 可以。 见:

您需要动态 SQL,例如:

DO
$do$
BEGIN
   EXECUTE format(
     'ALTER TABLE transactions
      ADD CONSTRAINT check_process_is_assigned CHECK (id <= %s OR process_id IS NOT NULL)'
    , (SELECT max(id) FROM transactions)
   );
END
$do$;

db小提琴here

这会基于 当前 最大值 id 创建一个 CHECK 约束。

也许NOT VALID constraint 会更好?不检查 现有行

ALTER TABLE transactions
      ADD CONSTRAINT check_process_is_assigned CHECK (process_id IS NOT NULL) NOT VALID;

但您必须“修复”在这种情况下更新的旧行。 (即,如果到目前为止为 NULL,则为 process_id 分配一个值。)参见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多