【问题标题】:SQL require literal value in foreign columnSQL 需要外部列中的文字值
【发布时间】:2018-03-30 23:52:34
【问题描述】:

是否可以在外键约束中要求特定的文字值?

例如

CREATE TABLE a (
  id bigserial primary key,
  b_id bigint not null,
  foreign key (b_id, true) references b(id, flag)
);

CREATE TABLE b (
  id bigserial primary key,
  flag boolean
);

我们希望a 中的行仅引用b 中的行且标志设置为true

【问题讨论】:

  • 我觉得做不到。也许您可以添加一个辅助列并将值设置为 _id 或 null 并在 A 中有一个 FK 引用 B 中的辅助列

标签: sql postgresql foreign-keys


【解决方案1】:

问题中的语法无效(请参阅CREATE TABLE)。可以得到想要的效果如下:

CREATE TABLE b (
    id bigserial,
    flag boolean,
    primary key(id, flag)
);

CREATE TABLE a (
    id bigserial primary key,
    b_id bigint not null,
    flag boolean default true check (flag),
    foreign key (b_id, flag) references b(id, flag)
);

【讨论】:

    【解决方案2】:

    可能想要一些类似的东西。我删除了多余的 a.id 列,使其更易于阅读。

    CREATE TABLE b (
      id bigserial not null,
      flag boolean not null,
      primary key (id),
      unique (id, flag)
    );
    

    id 上的主键约束防止重复的 ID 号。 id, flag 上的重叠约束允许这 pair 列成为外键约束的目标。

    CREATE TABLE a (
      b_id bigint not null,
      flag boolean not null default true
        check (flag = true),
      primary key (b_id, flag),
      foreign key (b_id, flag) references b (id, flag)
        on delete cascade
    );
    

    为了让a 中的行引用bflag 为真的行,a 中的每一行必须 flag 设置为真。 flag 的默认值和检查约束保证了这一点。

    现在让我们尝试插入一些行。

    insert into b (flag) values (true);
    insert into b (flag) values (true);
    insert into b (flag) values (false);
    

    到目前为止,一切都很好。现在为 a 设置一些行。

    insert into a (b_id, flag) values (1, true);
    insert into a (b_id, flag) values (2, true);
    

    但是这个应该失败了。

    insert into a (b_id, flag) values (3, true);
    
    --ERROR:  insert or update on table "a" violates foreign key constraint "a_b_id_fkey"
    --DETAIL:  Key (b_id, flag)=(3, t) is not present in table "b".
    

    而这个应该失败。

    insert into a (b_id, flag) values (3, false);
    
    --ERROR:  new row for relation "a" violates check constraint "a_flag_check"
    --DETAIL:  Failing row contains (3, f).
    

    还有一件事

    您需要考虑在更新表 b 中的标志时想要发生什么。你不能级联更新;这将导致a 中的一行引用b 中具有false 的行。

    update b set flag = false where id = 1 and flag = true;
    -- ERROR:  update or delete on table "b" violates foreign key constraint "a_b_id_fkey" on table "a"
    -- DETAIL:  Key (id, flag)=(1, t) is still referenced from table "a".
    

    如何处理取决于应用程序。在某些应用程序中,当b 中的行更新为false 时,删除a 中的行可能是合适的。在其他应用程序中,仅撤销b 的更新权限可能是合适的。 (还有其他选项。)无论如何,您都需要编写一个触发器。

    【讨论】:

      猜你喜欢
      • 2018-12-09
      • 1970-01-01
      • 2014-05-25
      • 2021-01-31
      • 1970-01-01
      • 2021-08-15
      • 2011-10-27
      • 2020-11-01
      相关资源
      最近更新 更多