Як створити зовнішній ключ у SQL Server?


243

Я ніколи не "кодував" ручним кодом створення об'єктів для 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
);

Коли я запускаю запит, я отримую цю помилку:

Msg 8139, Рівень 16, стан 0, рядок 9 Кількість стовпців посилань у зовнішньому ключі відрізняється від кількості стовпців, на які посилається, таблиці «питання_банку».

Чи можете ви помітити помилку?


2
FYI, завжди найкраще називати свої обмеження, особливо з використанням ORM.
Tracker1

Відповіді:


198
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)
);

37
Також може бути корисно назвати обмеження зовнішнього ключа. Це допомагає в усуненні несправностей із порушеннями файлів. Наприклад: "Іноземний ключ fk_questionbank_exams (question_exam_id) посилається на іспити (exam_id)"
Джон Василеф

31
Я згоден, іменування обмежень - це хороший план, але, принаймні, у SQL Server 2008 R2, синтаксис останнього рядка повинен бути "обмеженням fk_questionbank_exams іноземного ключа (question_exam_id) екзаменаційних посилань (exam_id)"
Джонатан Сайс

5
Дуже важливий момент, який слід зазначити, що створення зовнішнього ключа не створює індекс. Приєднання іншої таблиці до цієї може призвести до надзвичайно повільного запиту.
Rocklan

Я не впевнений, чому це по-іншому, але мені довелося робити CONSTRAINT fk_questionbank_exams ІНТЕРНЕТ КЛЮЧ (Question_exam_id)
ДОВІДКИ

Чи потрібно писати NON NULL для первинного ключа, або це явно, коли ми пишемо обмеження первинного ключа для стовпця, наприклад, я сиджу достатньо, щоб позначити стовпчик як основний ключ, щоб мати ненульове обмеження або повинен не вказано NON NULL, тобто написано явно?
гарі

326

І якщо ви просто хочете створити обмеження самостійно, ви можете використовувати ALTER TABLE

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

Я б не рекомендував синтаксис, згаданий Сарою Чіпсом для створення вбудованого тексту, просто тому, що я швидше назвав би свої власні обмеження.


19
Я знаю, що це померло старе ... але я потрапив сюди з пошуку Google і тому багато інших могли. Просто швидке виправлення: правильний спосіб посилання: СПОСОБИ MyOtherTable (MyOtherIDColumn)
PedroC88

3
MyTable_MyColumn_FK - найкраща практика іменування.
shaijut

70

Ви також можете назвати обмеження вашого зовнішнього ключа, використовуючи:

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

1
Використовуючи ORM, корисно було б назвати обмеження з декількома посиланнями на іноземну таблицю ... Використовували названі обмеження у властивостях з EF4, щоб я знав, який запис таблиці контактів призначений для покупця, продавця тощо
Tracker1

31

Мені подобається відповідь 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
)

Краще працює з "змінною таблицею MyTable (...)". :)
Sylvain Rodrigue

14
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
);

- Це теж буде працювати. Можливо, трохи інтуїтивніша конструкція?


1
Це те, що я роблю, але у мене виникає питання, чи є сенс додавати ключові слова "іноземний ключ"? - здається, працює без цього, наприклад: question_exam_id унікальний ідентифікатор не має нульових посилань на іспити (exam_id)
JSideris

Ключові слова "Іноземний ключ" необов'язкові. На мій погляд, це робить код читабельнішим.
Біжімон

8

Створення іноземного ключа на будь-якій таблиці

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)

8

Якщо ви хочете створити два стовпці таблиці у співвідношенні за допомогою запиту, спробуйте наступне:

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)

5

Як і ви, я зазвичай не створюю сторонні ключі вручну, але якщо мені чомусь потрібен скрипт, я зазвичай створюю його за допомогою студії управління сервером ms sql і перед тим, як зберегти, потім зміни, я вибираю дизайнер таблиці | Створити сценарій змін


4

Цей сценарій стосується створення таблиць із зовнішнім ключем, і я додав референтне обмеження цілісності sql-сервер .

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
);

3

Некромантування.
Власне, зробити це правильно - трохи складніше.

Спочатку потрібно перевірити, чи існує первинний ключ для стовпця, на який ви хочете встановити свій зовнішній ключ.

У цьому прикладі створюється зовнішній ключ таблиці 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 

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.