Bagaimana cara membuat kunci asing di SQL Server?

243

Saya tidak pernah "kode tangan" kode pembuatan objek untuk SQL Server dan decleration kunci asing tampaknya berbeda antara SQL Server dan Postgres. Ini sql saya sejauh ini:

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

Ketika saya menjalankan kueri saya mendapatkan kesalahan ini:

Msg 8139, Level 16, State 0, Line 9 Jumlah kolom referensi dalam kunci asing berbeda dari jumlah kolom yang direferensikan, tabel 'question_bank'.

Bisakah Anda menemukan kesalahan?

mmattax
sumber
2
FYI, selalu yang terbaik untuk menyebutkan kendala Anda, terutama dengan ORM yang digunakan.
Tracker1

Jawaban:

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)
);
John Boker
sumber
37
Juga dapat membantu untuk menyebutkan batasan kunci asing. Ini membantu mengatasi troubleshooting pelanggaran fk. Misalnya: "foreign key fk_questionbank_exams (question_exam_id) mereferensikan ujian (exam_id)"
John Vasileff
31
Saya setuju batasan penamaan adalah rencana yang bagus tetapi, dalam SQL Server 2008 R2 setidaknya, sintaks dari baris terakhir harus "constraint fk_questionbank_exams foreign key (question_exam_id) ujian referensi (exam_id)"
Jonathan Sayce
5
Poin yang sangat penting untuk dicatat yaitu membuat kunci asing tidak membuat indeks. Bergabung dengan tabel lain untuk ini dapat menghasilkan permintaan yang sangat lambat.
Rocklan
Saya tidak yakin mengapa ini berbeda, tetapi saya harus melakukan CONSTRAINT fk_questionbank_exams KUNCI LUAR NEGERI (question_exam_id) ujian REFERENSI (exam_id)
tenmiles
Apakah perlu untuk menulis NON NULL untuk kunci utama, atau ini eksplisit ketika kita menulis batasan kunci primer untuk kolom, misalnya, saya duduk cukup untuk menunjukkan kolom sebagai kunci utama untuk memiliki batasan non-nol atau harus NON NULL ditentukan, yaitu, ditulis secara eksplisit?
gary
326

Dan jika Anda hanya ingin membuat kendala sendiri, Anda dapat menggunakan ALTER TABLE

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

Saya tidak akan merekomendasikan sintaks yang disebutkan oleh Sara Chipps untuk pembuatan inline, hanya karena saya lebih suka menyebutkan kendala saya sendiri.

AlexCuse
sumber
19
Saya tahu ini sudah tua ... tapi saya dapatkan di sini dari pencarian google dan banyak lainnya bisa. Hanya perbaikan cepat: cara referensi yang benar adalah: REFERENSI MyOtherTable (MyOtherIDColumn)
PedroC88
3
MyTable_MyColumn_FK adalah praktik penamaan terbaik.
shaijut
70

Anda juga dapat memberi nama batasan kunci asing Anda dengan menggunakan:

CONSTRAINT your_name_here FOREIGN KEY (question_exam_id) REFERENCES EXAMS (exam_id)
Sara Chipps
sumber
1
Saat menggunakan ORM, ada baiknya menyebutkan batasan dengan beberapa referensi ke tabel asing ... Digunakan batasan bernama di properti dengan EF4, sehingga saya tahu entri tabel kontak mana yang ditujukan untuk pembeli, penjual, dll.
Tracker1
31

Saya suka jawaban AlexCuse, tetapi sesuatu yang harus Anda perhatikan setiap kali Anda menambahkan batasan kunci asing adalah bagaimana Anda ingin pembaruan ke kolom yang direferensikan di deretan tabel yang direferensikan untuk diperlakukan, dan terutama bagaimana Anda ingin menghapus baris dalam yang direferensikan meja untuk dirawat.

Jika batasan dibuat seperti ini:

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

.. lalu memperbarui atau menghapus dalam tabel referensi akan meledak dengan kesalahan jika ada baris yang sesuai dalam tabel referensi.

Itu mungkin perilaku yang Anda inginkan, tetapi dalam pengalaman saya, itu jauh lebih umum tidak.

Jika Anda membuatnya seperti ini:

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

..kemudian pembaruan dan penghapusan di tabel induk akan menghasilkan pembaruan dan menghapus baris yang sesuai di tabel referensi.

(Saya tidak menyarankan bahwa default harus diubah, default salah di sisi hati-hati, yang bagus. Saya hanya mengatakan itu adalah sesuatu yang harus selalu diperhatikan oleh orang yang menciptakan kendala .)

Ini bisa dilakukan, ketika membuat tabel, seperti ini:

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
)
Shavais
sumber
Bekerja lebih baik dengan "alter table 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
);

--Itu akan bekerja juga. Mungkin membangun konstruksi yang sedikit lebih intuitif?

Bijimon
sumber
1
Ini yang saya lakukan, tetapi saya punya pertanyaan, Apakah ada gunanya menambahkan kata kunci "kunci asing"? - tampaknya berfungsi tanpa itu, misalnya: question_exam_id uniqueidentifier bukan ujian referensi nol (exam_id)
JSideris
Kata kunci "Kunci asing" adalah opsional. Menurut pendapat saya itu membuat kode lebih mudah dibaca.
Bijimon
8

Untuk membuat kunci asing di tabel apa pun

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)
Abhishek Jaiswal
sumber
8

Jika Anda ingin membuat dua kolom tabel menjadi suatu hubungan dengan menggunakan kueri coba yang berikut ini:

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)
Md Ashikul Islam
sumber
5

Seperti Anda, saya biasanya tidak membuat kunci asing dengan tangan, tetapi jika karena alasan tertentu saya memerlukan skrip untuk melakukannya maka saya biasanya membuatnya menggunakan ms sql server manajemen studio dan sebelum menyimpan kemudian berubah, saya memilih Table Designer | Buat Skrip Perubahan

Vitor Silva
sumber
4

Script ini adalah tentang membuat tabel dengan kunci asing dan saya menambahkan kendala integritas referensial 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
);
elkhayari abderrazzak
sumber
3

Necromancing.
Sebenarnya, melakukan ini dengan benar sedikit lebih rumit.

Pertama-tama Anda perlu memeriksa apakah kunci utama ada untuk kolom yang Anda ingin atur kunci asing Anda untuk referensi.

Dalam contoh ini, kunci asing pada tabel T_ZO_SYS_Language_Forms dibuat, merujuk 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 
Stefan Steiger
sumber
2

Saya selalu menggunakan sintaks ini untuk membuat batasan kunci asing antara 2 tabel

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

yaitu

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