SQL Server'da nasıl yabancı anahtar oluştururum?


243

Ben asla SQL Server için "el kodlu" nesne oluşturma kodu var ve yabancı anahtar decleration SQL Server ve Postgres arasında görünüşte farklı. İşte benim sql şimdiye kadar:

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

Sorguyu çalıştırdığımda bu hatayı alıyorum:

Msg 8139, Seviye 16, Durum 0, Satır 9 Yabancı anahtardaki başvuru sütunlarının sayısı başvurulan sütun sayısından, 'question_bank' tablosundan farklı.

Hatayı tespit edebilir misiniz?


2
FYI, özellikle kullanımdaki ORM'lerle kısıtlamalarınızı her zaman adlandırmak en iyisidir.
Tracker1

Yanıtlar:


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
Yabancı anahtar kısıtlamasını adlandırmak da yararlı olabilir. Bu, ihlallerin giderilmesinde yardımcı olur. Örneğin: "yabancı anahtar fk_questionbank_exams (question_exam_id) başvuru sınavlarına (exam_id)"
John Vasileff

31
En azından SQL Server 2008 R2 içinde, iyi bir plan kısıtlamaları olan adlandırma ama katılıyorum, son satırın sözdizimi "kısıt yabancı anahtar (question_exam_id) başvuruları sınav (exam_id) fk_questionbank_exams" olmak zorundadır
Jonathan Sayce

5
Gelmez yabancı anahtar yaratıyor nota Çok önemli bir nokta değil bir dizin oluşturun. Bu tabloya başka bir tablo eklemek çok yavaş bir sorgu ile sonuçlanabilir.
Rocklan

Neden farklı olduğundan emin değilim, ancak CONSTRAINT yapmak zorunda kaldım fk_questionbank_exams YABANCI ANAHTAR (question_exam_id) REFERANSLAR sınavları (exam_id)
tenmiles 29:16

Birincil anahtar için NULL OLMAMASI gerekli mi yoksa sütun için birincil anahtar kısıtlamasını yazdığımızda bu açık mı, örneğin, null olmayan bir kısıtlamaya sahip bir sütunu birincil anahtar olarak gösterecek kadar oturuyorum veya NULL belirtilmemiş, yani açıkça yazılmış mı?
gary

326

Kısıtlamayı kendi başına oluşturmak istiyorsanız, ALTER TABLE'ı kullanabilirsiniz.

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

Sadece kendi kısıtlamalarımı adlandırmayı tercih ettiğim için, Sara Chipps tarafından satır içi oluşturma için bahsedilen sözdizimini tavsiye etmem.


19
Bunun ölü eski olduğunu biliyorum ... ama buraya bir google aramasından geldim ve birçoğu yapabilir. Sadece hızlı bir düzeltme: referans için doğru yol: REFERANSLAR MyOtherTable (MyOtherIDColumn)
PedroC88

3
MyTable_MyColumn_FK en iyi adlandırma uygulamasıdır.
shaijut

70

Ayrıca, yabancı anahtar kısıtlamanızı aşağıdakileri kullanarak adlandırabilirsiniz:

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

1
Bir ORM kullanırken, yabancı tabloya birden fazla başvuru ile kısıtlamalar adlandırılmış olması yararlı olur ... EF4 ile özelliklerde adlandırılmış kısıtlamalar kullanıldı, böylece hangi kişi tablosu girişinin alıcı, satıcı vb. İçin olduğunu biliyordum
Tracker1

31

AlexCuse'un cevabını beğendim, ancak her ne zaman bir yabancı anahtar kısıtlaması eklediğinizde dikkat edilmesi gereken bir şey, başvurulan tablonun bir satırındaki başvurulan sütuna yapılan güncellemelerin nasıl ele alınacağını ve özellikle başvurulan satırların silinmesini nasıl istediğinizdir tedavi edilecek tablo.

Eğer böyle bir kısıtlama oluşturulursa:

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

.. daha sonra referans tablosunda karşılık gelen bir satır varsa referans alınan tablodaki güncellemeler veya silmeler bir hatayla patlar.

İstediğiniz davranış bu olabilir, ancak benim deneyimime göre, çok daha yaygın değil.

Bunun yerine şu şekilde oluşturursanız:

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

.. daha sonra üst tablodaki güncellemeler ve silmeler referans tablosundaki ilgili satırların güncellenmesine ve silinmesine neden olur.

(Temerrütün değiştirilmesi gerektiğini önermiyorum, temkinli taraftaki varsayılan hatalar, ki bu iyi. Ben sadece constainlar yaratan bir kişinin her zaman dikkat etmesi gereken bir şey olduğunu söylüyorum .)

Bu arada, bir tablo oluştururken şu şekilde yapılabilir:

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
)

"Tabloyu değiştir MyTable (...)" ile daha iyi çalışır. :)
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
);

- Bu da işe yarayacak. Belki biraz daha sezgisel bir yapı?


1
Yaptığım şey bu, ama bir sorum var, "Yabancı anahtar" anahtar kelimeleri eklemenin bir anlamı var mı? - bu olmadan çalışıyor gibi görünüyor, örneğin: question_exam_id uniqueidentifier null referans sınavları değil (exam_id)
JSideris

"Yabancı anahtar" anahtar kelimeleri isteğe bağlıdır. Benim görüşümde kodu daha okunabilir kılıyor.
Bijimon

8

Herhangi bir tabloda yabancı anahtar oluşturmak için

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

Bir sorgu kullanarak bir ilişki içine iki tablonun sütunları oluşturmak istiyorsanız aşağıdakileri deneyin:

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

Senin gibi, ben genellikle yabancı anahtarları el ile oluşturmuyorum, ama herhangi bir nedenle betiğe ihtiyacım varsa bunu yapmak için genellikle ms sql server yönetim stüdyosunu kullanarak oluştururum ve kaydetmeden önce değişiklikleri seçerim. Değişiklik Komut Dosyası Oluştur


4

Bu komut dosyası yabancı anahtar içeren tablolar oluşturmakla ilgilidir ve başvuru bütünlüğü kısıtlaması sql-server ekledim .

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

Necromancing.
Aslında, bunu doğru yapmak biraz daha zordur.

İlk olarak, yabancı anahtarınızı başvurmak istediğiniz sütun için birincil anahtarın var olup olmadığını kontrol etmeniz gerekir.

Bu örnekte, dbo.T_SYS_Language_Forms.LANG_UID değerine bakılarak T_ZO_SYS_Language_Forms tablosunda yabancı bir anahtar oluşturulur.

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

Her zaman bu sözdizimini 2 tablo arasında yabancı anahtar kısıtı oluşturmak için kullanıyorum

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

yani

Alter Table tblEmployee
Add constraint tblEmployee_DepartmentID_FK
foreign key (DepartmentID) references tblDepartment (ID)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.