Sql 使用外部复合键,是否可以引用列和固定值?

Sql 使用外部复合键,是否可以引用列和固定值?,sql,database,postgresql,database-design,foreign-keys,Sql,Database,Postgresql,Database Design,Foreign Keys,以下是我的用例: 我有4张桌子: CREATE TABLE A ( name character(20) NOT NULL, id integer NOT NULL, CONSTRAINT a_pkey PRIMARY KEY (id) ) CREATE TABLE B ( name character(20) NOT NULL, id integer NOT NULL, CONSTRAINT b_pkey PRIMARY KEY (id) ) CREATE TABL

以下是我的用例:

我有4张桌子:

CREATE TABLE A
(
  name character(20) NOT NULL,
  id integer NOT NULL,
  CONSTRAINT a_pkey PRIMARY KEY (id)
)

CREATE TABLE B
(
  name character(20) NOT NULL,
  id integer NOT NULL,
  CONSTRAINT b_pkey PRIMARY KEY (id)
)

CREATE TABLE C
(
  name character(20) NOT NULL,
  id integer NOT NULL,
  CONSTRAINT c_pkey PRIMARY KEY (id)
)

CREATE TABLE X
(
  type character(20) NOT NULL,
  other_id integer NOT NULL,
  id integer NOT NULL,
  CONSTRAINT "X_PK" PRIMARY KEY (id)
)
表X中的“other_id”可以是表A、B或C中任何一个的“id”。表X中的“type”列应指示“other_id”中存储了表A、B或C中的哪一个“id”

表x中的示例数据:

type  other_id  id
"A"    1         1
"B"    1         2
"C"    1         3
"A"    2         4
尝试使用固定值在表X-A、X-B和X-C之间创建复合FK,如下所示

ALTER TABLE x
ADD CONSTRAINT X_A_FK FOREIGN KEY (other_id, type) REFERENCES a (id, 'A') ON DELETE CASCADE
但是我得到了这个错误(所有FK都有相同的问题):

错误:“A”处或附近出现语法错误


我的问题是,使用外部复合键,是否可以引用列和固定值?如果不是的话,有什么更好的方法来解决这个问题呢?

根据您遇到的错误,这是不可能的。但至少有两种选择可以实现相同的效果:

  • 您可以在
    类型上添加
    检查
    约束,并在
    (其他id)
    (其他id,类型)
    上强制使用外键

  • 您可以添加直接强制伪外键的约束触发器


  • 我建议另一种设计:

    CREATE TABLE a (
      a_id integer PRIMARY KEY -- pk is NOT NULL automatically
     ,a    text NOT NULL
    );
    
    CREATE TABLE b ( ...);
    CREATE TABLE c ( ...);
    
    CREATE TABLE x (
      x_id integer PRIMARY KEY        -- or maybe a serial?
     ,a_id integer REFERENCES a(a_id) -- can be NULL
     ,b_id integer REFERENCES b(b_id)
     ,c_id integer REFERENCES c(c_id)
    );
    
    主要的一点是在设计中有三列(
    a\u id,b\u id,c\u id
    ),而不是两列(
    other\u id,type
    )。与人们的想法相反,这需要更少的磁盘空间,同时更干净、更简单。您不需要额外的约束或索引来强制引用完整性。

    如果您想强制执行,一次最多可以链接一个(
    a,b,c
    ),请添加一个:

    看起来很长,但非常便宜和简单

    如果您希望强制一次只能链接一个(
    a,b,c
    ),请修改为:

    ALTER TABLE x ADD CONSTRAINT x_exactly1_fk
    CHECK (a_id IS NULL AND b_id IS NULL AND c_id IS NOT NULL
        OR b_id IS NULL AND c_id IS NULL AND a_id IS NOT NULL
        OR a_id IS NULL AND c_id IS NULL AND b_id IS NOT NULL)
    
    对于不仅仅是几列的,我会使用:

    ALTER TABLE x ADD CONSTRAINT x_exactly1_fk
    CHECK ((a_id IS NULL)::int
         + (b_id IS NULL)::int
         + (c_id IS NULL)::int = 1)  -- or <= 1 for the former case
    
    ALTER TABLE x ADD CONSTRAINT x_精确1_fk
    检查((a_id为空)::int
    +(b_id为空)::int
    
    +(c_id为NULL)::int=1)--或者感谢您的快速回复,请您对您的第一个解决方案进行详细说明,我不知道如何实现它。我可能应该补充说我需要3个FK,我在问题中只提到了一个,因为我尝试制作的第一个FK失败了。谢谢你的回复。我曾考虑添加额外的可空列,但不确定这是否是一种好的做法,因为如果将来有更多的表,如a、B和C,我将需要创建更多可空列。我非常感谢您的检查建议,它非常方便且干净,可以确保数据的完整性。@IdaN:如果您有几十个引用表,并且只有一个表适用,
    (id,type)
    会更有利。不过,我想问一个问题,您是否不能将引用的表捆绑到一个(中间)表中或使用…在我的例子中,我只有几个表,您当前的解决方案完全适用。我问这个问题只是想知道你的看法,在一个比两张桌子大得多的案例中,什么是更好的方法。
    ALTER TABLE x ADD CONSTRAINT x_exactly1_fk
    CHECK ((a_id IS NULL)::int
         + (b_id IS NULL)::int
         + (c_id IS NULL)::int = 1)  -- or <= 1 for the former case