Wie erstelle ich einen Fremdschlüssel in SQL Server?

243

Ich habe noch nie einen Code für die Objekterstellung für SQL Server "handcodiert", und die Dekleration von Fremdschlüsseln scheint sich zwischen SQL Server und Postgres zu unterscheiden. Hier ist meine SQL bisher:

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

Wenn ich die Abfrage ausführe, wird folgende Fehlermeldung angezeigt:

Meldung 8139, Ebene 16, Status 0, Zeile 9 Die Anzahl der referenzierenden Spalten im Fremdschlüssel unterscheidet sich von der Anzahl der referenzierten Spalten in der Tabelle 'question_bank'.

Können Sie den Fehler erkennen?

mmattax
quelle
2
Zu Ihrer Information, es ist immer am besten, Ihre Einschränkungen zu benennen, insbesondere bei verwendeten ORMs.
Tracker1

Antworten:

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
quelle
37
Es kann auch hilfreich sein, die Fremdschlüsseleinschränkung zu benennen. Dies hilft bei der Fehlerbehebung bei fk-Verstößen. Zum Beispiel: "Fremdschlüssel fk_questionbank_exams (question_exam_id) verweist auf Prüfungen (exam_id)"
John Vasileff
31
Ich bin damit einverstanden, dass das Benennen von Einschränkungen ein guter Plan ist, aber zumindest in SQL Server 2008 R2 muss die Syntax der letzten Zeile "Einschränkung fk_questionbank_exams Fremdschlüssel (question_exam_id) referenziert Prüfungen (exam_id)" sein
Jonathan Sayce
5
Ein sehr wichtiger Punkt beim Erstellen des Fremdschlüssels ist, dass kein Index erstellt wird. Das Verknüpfen einer anderen Tabelle mit dieser kann zu einer extrem langsamen Abfrage führen.
Rocklan
Ich bin nicht sicher, warum es anders ist, aber ich musste CONSTRAINT fk_questionbank_exams AUSLÄNDISCHER SCHLÜSSEL (question_exam_id) REFERENZEN Prüfungen (exam_id)
zehn Meilen
Ist es notwendig, NON NULL für den Primärschlüssel zu schreiben, oder ist dies explizit, wenn wir die Primärschlüsseleinschränkung für die Spalte schreiben, z. B. sitze ich genug, um eine Spalte als Primärschlüssel zu bezeichnen, um eine Nicht-Null-Einschränkung zu haben oder muss die NON NULL angegeben werden, dh explizit geschrieben?
Gary
326

Und wenn Sie die Einschränkung nur selbst erstellen möchten, können Sie ALTER TABLE verwenden

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

Ich würde die von Sara Chipps erwähnte Syntax für die Inline-Erstellung nicht empfehlen, nur weil ich lieber meine eigenen Einschränkungen benennen möchte.

AlexCuse
quelle
19
Ich weiß, dass dies tot alt ist ... aber ich bin von einer Google-Suche hierher gekommen und so viele andere konnten es. Nur eine schnelle Lösung: Die richtige Referenz ist: REFERENZEN MyOtherTable (MyOtherIDColumn)
PedroC88
3
MyTable_MyColumn_FK ist die beste Benennungspraxis.
Shaijut
70

Sie können Ihre Fremdschlüsseleinschränkung auch folgendermaßen benennen:

CONSTRAINT your_name_here FOREIGN KEY (question_exam_id) REFERENCES EXAMS (exam_id)
Sara Chipps
quelle
1
Bei Verwendung eines ORM ist es hilfreich, benannte Einschränkungen mit mehreren Verweisen auf die Fremdtabelle zu haben ... Verwendete benannte Einschränkungen in Eigenschaften mit EF4, damit ich wusste, welcher Kontakttabelleneintrag für Käufer, Verkäufer usw. war.
Tracker1
31

Ich mag die Antwort von AlexCuse, aber etwas, auf das Sie achten sollten, wenn Sie eine Fremdschlüsseleinschränkung hinzufügen, ist, wie Aktualisierungen der referenzierten Spalte in einer Zeile der referenzierten Tabelle behandelt werden sollen und insbesondere, wie Sie Zeilen in der referenzierten Tabelle löschen möchten zu behandelnder Tisch.

Wenn eine Einschränkung wie folgt erstellt wird:

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

.. dann werden Aktualisierungen oder Löschungen in der referenzierten Tabelle mit einem Fehler angezeigt, wenn die referenzierende Tabelle eine entsprechende Zeile enthält.

Das mag das Verhalten sein, das Sie wollen, aber meiner Erfahrung nach ist es viel häufiger nicht so.

Wenn Sie es stattdessen so erstellen:

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

..dann führen Aktualisierungen und Löschungen in der übergeordneten Tabelle zu Aktualisierungen und Löschungen der entsprechenden Zeilen in der Referenzierungstabelle.

(Ich schlage nicht vor, dass die Standardeinstellung geändert werden sollte, die Standardeinstellung ist auf der Seite der Vorsicht, was gut ist. Ich sage nur, dass eine Person, die Konstanten erstellt, immer darauf achten sollte .)

Dies kann übrigens beim Erstellen einer Tabelle wie folgt erfolgen:

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
quelle
Funktioniert besser mit "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
);

- Das wird auch funktionieren. Pehaps ein bisschen intuitiver konstruieren?

Bijimon
quelle
1
Dies ist, was ich tue, aber ich habe eine Frage: Gibt es einen Grund, die Schlüsselwörter "Fremdschlüssel" hinzuzufügen? - es scheint ohne das zu funktionieren, zB: question_exam_id uniqueidentifier not null referenziert prüfungen (exam_id)
JSideris
Die Schlüsselwörter "Fremdschlüssel" sind optional. Meiner Meinung nach macht es den Code lesbarer.
Bijimon
8

So erstellen Sie einen Fremdschlüssel für eine beliebige Tabelle

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

Wenn Sie mithilfe einer Abfrage zwei Tabellenspalten zu einer Beziehung erstellen möchten, versuchen Sie Folgendes:

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

Wie Sie erstelle ich normalerweise keine Fremdschlüssel von Hand, aber wenn ich aus irgendeinem Grund das Skript dazu benötige, erstelle ich es normalerweise mit ms sql server management studio und bevor ich Änderungen speichere, wähle ich Table Designer | Änderungsskript generieren

Vitor Silva
quelle
4

In diesem Skript geht es darum, Tabellen mit Fremdschlüssel zu erstellen, und ich habe den SQL-Server für die Einschränkung der referenziellen Integrität hinzugefügt .

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

Nekromantie.
Eigentlich ist es etwas schwieriger, dies richtig zu machen.

Sie müssen zunächst überprüfen, ob der Primärschlüssel für die Spalte vorhanden ist, auf die Sie Ihren Fremdschlüssel verweisen möchten.

In diesem Beispiel wird ein Fremdschlüssel in der Tabelle T_ZO_SYS_Language_Forms erstellt, der auf dbo.T_SYS_Language_Forms.LANG_UID verweist

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

Ich verwende immer diese Syntax, um die Fremdschlüsseleinschränkung zwischen zwei Tabellen zu erstellen

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

dh

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