【问题标题】:How do I create a foreign key in SQL Server?如何在 SQL Server 中创建外键?
【发布时间】:2010-09-08 02:32:25
【问题描述】:

我从来没有为 SQL Server“手工编码”过对象创建代码,而且 SQL Server 和 Postgres 之间的外键解密似乎不同。到目前为止,这是我的 sql:

drop table exams;
drop table question_bank;
drop table anwser_bank;

create table exams
(
    exam_id uniqueidentifier primary key,
    exam_name varchar(50),
);
create table question_bank
(
    question_id uniqueidentifier primary key,
    question_exam_id uniqueidentifier not null,
    question_text varchar(1024) not null,
    question_point_value decimal,
    constraint question_exam_id foreign key references exams(exam_id)
);
create table anwser_bank
(
    anwser_id           uniqueidentifier primary key,
    anwser_question_id  uniqueidentifier,
    anwser_text         varchar(1024),
    anwser_is_correct   bit
);

当我运行查询时,我得到了这个错误:

消息 8139,第 16 级,状态 0,第 9 行 中的引用列数 外键与数量不同 引用的列、表 'question_bank'。

你能发现错误吗?

【问题讨论】:

  • 仅供参考,总是最好为您的约束命名,尤其是在使用 ORM 时。

标签: sql sql-server tsql


【解决方案1】:

我总是使用这种语法在 2 个表之间创建外键约束

Alter Table ForeignKeyTable
Add constraint `ForeignKeyTable_ForeignKeyColumn_FK`
`Foreign key (ForeignKeyColumn)` references `PrimaryKeyTable (PrimaryKeyColumn)`

Alter Table tblEmployee
Add constraint tblEmployee_DepartmentID_FK
foreign key (DepartmentID) references tblDepartment (ID)

【讨论】:

    【解决方案2】:

    如果您想通过使用查询将两个表的列创建为关系,请尝试以下操作:

    Alter table Foreign_Key_Table_name add constraint 
    Foreign_Key_Table_name_Columnname_FK
    Foreign Key (Column_name) references 
    Another_Table_name(Another_Table_Column_name)
    

    【讨论】:

      【解决方案3】:

      这个脚本是关于使用外键创建表的,我添加了引用完整性约束sql-server

      create table exams
      (  
          exam_id int primary key,
          exam_name varchar(50),
      );
      
      create table question_bank 
      (
          question_id int primary key,
          question_exam_id int not null,
          question_text varchar(1024) not null,
          question_point_value decimal,
          constraint question_exam_id_fk
             foreign key references exams(exam_id)
                     ON DELETE CASCADE
      );
      

      【讨论】:

        【解决方案4】:

        我喜欢 AlexCuse 的回答,但是当您添加外键约束时,您应该注意的是,您希望如何处理被引用表的一行中被引用列的更新,尤其是如何删除行在要处理的引用表中。

        如果像这样创建约束:

        alter table MyTable
        add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) 
        references MyOtherTable(PKColumn)
        

        .. 那么如果引用表中有对应的行,则引用表中的更新或删除操作会报错。

        这可能是您想要的行为,但根据我的经验,通常不是。

        如果你改为这样创建它:

        alter table MyTable
        add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) 
        references MyOtherTable(PKColumn)
        on update cascade 
        on delete cascade
        

        ..然后父表中的更新和删除将导致引用表中相应行的更新和删除。

        (我并不是建议应该更改默认值,默认错误是出于谨慎考虑,这很好。我只是说这是创建约束的人应该做的事情时刻注意。)

        顺便说一句,这可以在创建表时完成,如下所示:

        create table ProductCategories (
          Id           int identity primary key,
          ProductId    int references Products(Id)
                       on update cascade on delete cascade
          CategoryId   int references Categories(Id) 
                       on update cascade on delete cascade
        )
        

        【讨论】:

        • 与“alter table MyTable (...)”配合使用效果更好。 :)
        【解决方案5】:
        create table question_bank
        (
            question_id uniqueidentifier primary key,
            question_exam_id uniqueidentifier not null,
            question_text varchar(1024) not null,
            question_point_value decimal,
            constraint fk_questionbank_exams foreign key (question_exam_id) references exams (exam_id)
        );
        

        【讨论】:

        • 命名外键约束也很有帮助。这有助于解决 fk 违规问题。例如:“外键 fk_questionbank_exams (question_exam_id) 引用考试 (exam_id)”
        • 我同意命名约束是一个好计划,但至少在 SQL Server 2008 R2 中,最后一行的语法必须是“约束 fk_questionbank_exams 外键 (question_exam_id) 参考考试 (exam_id)”
        • 非常重要的一点要注意,创建外键并创建索引。将另一个表连接到该表可能会导致查询速度极慢。
        • 我不知道为什么它不同,但我不得不做 CONSTRAINT fk_questionbank_exams FOREIGN KEY (question_exam_id) REFERENCES Exams (exam_id)
        • 是否有必要为主键写一个 NON NULL ,或者当我们为列写主键约束时这是明确的,例如,我坐得足以将一列表示为主键有非空约束还是必须指定 NON NULL,即显式编写?
        【解决方案6】:

        在任何表上创建外键

        ALTER TABLE [SCHEMA].[TABLENAME] ADD FOREIGN KEY (COLUMNNAME) REFERENCES [TABLENAME](COLUMNNAME)
        EXAMPLE
        ALTER TABLE [dbo].[UserMaster] ADD FOREIGN KEY (City_Id) REFERENCES [dbo].[CityMaster](City_Id)
        

        【讨论】:

          【解决方案7】:

          死灵术。
          实际上,正确地执行此操作有点棘手。

          您首先需要检查要设置外键引用的列的主键是否存在。

          在本例中,创建表 T_ZO_SYS_Language_Forms 的外键,引用 dbo.T_SYS_Language_Forms.LANG_UID

          -- First, chech if the table exists...
          IF 0 < (
              SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES 
              WHERE TABLE_TYPE = 'BASE TABLE'
              AND TABLE_SCHEMA = 'dbo'
              AND TABLE_NAME = 'T_SYS_Language_Forms'
          )
          BEGIN
              -- Check for NULL values in the primary-key column
              IF 0 = (SELECT COUNT(*) FROM T_SYS_Language_Forms WHERE LANG_UID IS NULL)
              BEGIN
                  ALTER TABLE T_SYS_Language_Forms ALTER COLUMN LANG_UID uniqueidentifier NOT NULL 
          
                  -- No, don't drop, FK references might already exist...
                  -- Drop PK if exists 
                  -- ALTER TABLE T_SYS_Language_Forms DROP CONSTRAINT pk_constraint_name 
                  --DECLARE @pkDropCommand nvarchar(1000) 
                  --SET @pkDropCommand = N'ALTER TABLE T_SYS_Language_Forms DROP CONSTRAINT ' + QUOTENAME((SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
                  --WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' 
                  --AND TABLE_SCHEMA = 'dbo' 
                  --AND TABLE_NAME = 'T_SYS_Language_Forms' 
                  ----AND CONSTRAINT_NAME = 'PK_T_SYS_Language_Forms' 
                  --))
                  ---- PRINT @pkDropCommand 
                  --EXECUTE(@pkDropCommand) 
          
                  -- Instead do
                  -- EXEC sp_rename 'dbo.T_SYS_Language_Forms.PK_T_SYS_Language_Forms1234565', 'PK_T_SYS_Language_Forms';
          
          
                  -- Check if they keys are unique (it is very possible they might not be) 
                  IF 1 >= (SELECT TOP 1 COUNT(*) AS cnt FROM T_SYS_Language_Forms GROUP BY LANG_UID ORDER BY cnt DESC)
                  BEGIN
          
                      -- If no Primary key for this table
                      IF 0 =  
                      (
                          SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
                          WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' 
                          AND TABLE_SCHEMA = 'dbo' 
                          AND TABLE_NAME = 'T_SYS_Language_Forms' 
                          -- AND CONSTRAINT_NAME = 'PK_T_SYS_Language_Forms' 
                      )
                          ALTER TABLE T_SYS_Language_Forms ADD CONSTRAINT PK_T_SYS_Language_Forms PRIMARY KEY CLUSTERED (LANG_UID ASC)
                      ;
          
                      -- Adding foreign key
                      IF 0 = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME = 'FK_T_ZO_SYS_Language_Forms_T_SYS_Language_Forms') 
                          ALTER TABLE T_ZO_SYS_Language_Forms WITH NOCHECK ADD CONSTRAINT FK_T_ZO_SYS_Language_Forms_T_SYS_Language_Forms FOREIGN KEY(ZOLANG_LANG_UID) REFERENCES T_SYS_Language_Forms(LANG_UID); 
                  END -- End uniqueness check
                  ELSE
                      PRINT 'FSCK, this column has duplicate keys, and can thus not be changed to primary key...' 
              END -- End NULL check
              ELSE
                  PRINT 'FSCK, need to figure out how to update NULL value(s)...' 
          END 
          

          【讨论】:

            【解决方案8】:

            如果你只是想自己创建约束,你可以使用 ALTER TABLE

            alter table MyTable
            add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) references MyOtherTable(PKColumn)
            

            我不推荐 Sara Chipps 提到的用于内联创建的语法,因为我宁愿命名我自己的约束。

            【讨论】:

            • 我知道这已经过时了......但我是通过谷歌搜索来到这里的,其他很多人都可以。快速修复:正确的引用方式是:REFERENCES MyOtherTable(MyOtherIDColumn)
            • MyTable_MyColumn_FK 是最佳命名实践。
            【解决方案9】:

            您还可以使用以下方法命名外键约束:

            CONSTRAINT your_name_here FOREIGN KEY (question_exam_id) REFERENCES EXAMS (exam_id)
            

            【讨论】:

            • 使用 ORM 时,使用对外部表的多个引用来命名约束会很有帮助...在 EF4 的属性中使用命名约束,这样我就知道哪个联系人表条目是针对买方、卖方的等。
            【解决方案10】:
            create table question_bank
            (
                question_id uniqueidentifier primary key,
                question_exam_id uniqueidentifier not null constraint fk_exam_id foreign key references exams(exam_id),
                question_text varchar(1024) not null,
                question_point_value decimal
            );
            

            --这也行。也许更直观的构造?

            【讨论】:

            • 这是我做的,但我有一个问题,添加“外键”关键字有什么意义吗? - 没有它似乎可以工作,例如:question_exam_id uniqueidentifier not null references Exams(exam_id)
            • “外键”关键字是可选的。在我看来,它使代码更具可读性。
            【解决方案11】:

            和你一样,我通常不手动创建外键,但如果出于某种原因我需要脚本来创建它,我通常使用 ms sql server management studio 创建它,然后在保存更改之前,我选择表设计器 |生成更改脚本

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-11-05
              • 1970-01-01
              • 2021-11-23
              • 2014-07-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多