Come posso creare una chiave esterna in SQL Server?
-
09-06-2019 - |
Domanda
Non ho mai "codificato manualmente" il codice di creazione di oggetti per SQL Server e la declerazione delle chiavi esterne è apparentemente diversa tra SQL Server e Postgres.Ecco il mio SQL finora:
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
);
Quando eseguo la query ottengo questo errore:
MSG 8139, Livello 16, Stato 0, riga 9 Numero di colonne di riferimento in chiave esterna differisce dal numero di colonne referenziate, tabella "question_bank".
Riesci a individuare l'errore?
Soluzione
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)
);
Altri suggerimenti
E se vuoi semplicemente creare il vincolo da solo, puoi usare ALTER TABLE
alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) references MyOtherTable(PKColumn)
Non consiglierei la sintassi menzionata da Sara Chipps per la creazione in linea, solo perché preferirei nominare i miei vincoli.
Puoi anche nominare il vincolo di chiave esterna utilizzando:
CONSTRAINT your_name_here FOREIGN KEY (question_exam_id) REFERENCES EXAMS (exam_id)
Mi piace la risposta di AlexCuse, ma qualcosa a cui dovresti prestare attenzione ogni volta che aggiungi un vincolo di chiave esterna è il modo in cui desideri che vengano trattati gli aggiornamenti alla colonna di riferimento in una riga della tabella di riferimento, e in particolare il modo in cui desideri eliminare le righe nella tabella di riferimento tavola da trattare.
Se viene creato un vincolo in questo modo:
alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn )
references MyOtherTable(PKColumn)
..Poi gli aggiornamenti o le eliminazioni nella tabella di riferimento verranno visualizzati con un errore se è presente una riga corrispondente nella tabella di riferimento.
Potrebbe essere il comportamento che desideri, ma nella mia esperienza, molto più comunemente non lo è.
Se invece lo crei in questo modo:
alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn )
references MyOtherTable(PKColumn)
on update cascade
on delete cascade
..quindi gli aggiornamenti e le eliminazioni nella tabella padre comporteranno aggiornamenti ed eliminazioni delle righe corrispondenti nella tabella di riferimento.
(Non sto suggerendo che l'impostazione predefinita debba essere modificata, l'impostazione predefinita pecca di cautela, il che è positivo.Sto solo dicendo che è qualcosa che una persona che crea fissa bisognerebbe sempre prestare attenzione.)
Questo può essere fatto, tra l'altro, quando si crea una tabella, in questo modo:
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
)
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
);
--Funzionerà anche quello.Forse un costrutto un po' più intuitivo?
Se desideri creare due colonne della tabella in una relazione utilizzando una query, prova quanto segue:
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)
Per creare una chiave esterna su qualsiasi tabella
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)
Come te, di solito non creo chiavi straniere a mano, ma se per qualche motivo ho bisogno che lo script lo crei di solito utilizzando MS SQL Server Management Studio e prima di salvare e poi cambia, seleziono tabella designer | Generare script di cambiamento
Questo script riguarda la creazione di tabelle con chiave esterna e ho aggiunto un vincolo di integrità referenziale server 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
);
Negromanzia.
In realtà, farlo correttamente è un po’ più complicato.
Devi prima verificare se esiste la chiave primaria per la colonna a cui vuoi impostare la chiave esterna a cui fare riferimento.
In questo esempio, viene creata una chiave esterna sulla tabella T_ZO_SYS_Language_Forms, che fa riferimento a 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