Como faço para criar uma chave estrangeira no SQL Server?
-
09-06-2019 - |
Pergunta
Eu nunca "codifiquei manualmente" o código de criação de objetos para o SQL Server e a declaração de chave estrangeira é aparentemente diferente entre o SQL Server e o Postgres.Aqui está meu sql até agora:
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 executo a consulta, recebo este erro:
MSG 8139, Nível 16, Estado 0, linha 9 Número de colunas de referência em chave estrangeira difere do número de colunas referenciadas, tabela 'question_bank'.
Você consegue identificar o erro?
Solução
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)
);
Outras dicas
E se você quiser apenas criar a restrição por conta própria, você pode usar ALTER TABLE
alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) references MyOtherTable(PKColumn)
Eu não recomendaria a sintaxe mencionada por Sara Chipps para criação inline, só porque prefiro nomear minhas próprias restrições.
Você também pode nomear sua restrição de chave estrangeira usando:
CONSTRAINT your_name_here FOREIGN KEY (question_exam_id) REFERENCES EXAMS (exam_id)
Gosto da resposta do AlexCuse, mas algo que você deve prestar atenção sempre que adicionar uma restrição de chave estrangeira é como você deseja que as atualizações na coluna referenciada em uma linha da tabela referenciada sejam tratadas e, especialmente, como você deseja que as exclusões de linhas na tabela referenciada sejam tratadas. tabela a ser tratada.
Se uma restrição for criada assim:
alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn )
references MyOtherTable(PKColumn)
..então atualizações ou exclusões na tabela referenciada gerarão um erro se houver uma linha correspondente na tabela de referência.
Esse pode ser o comportamento que você deseja, mas, na minha experiência, é muito mais comum que não seja.
Se você criar assim:
alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn )
references MyOtherTable(PKColumn)
on update cascade
on delete cascade
..então atualizações e exclusões na tabela pai resultarão em atualizações e exclusões das linhas correspondentes na tabela de referência.
(Não estou sugerindo que o padrão deva ser alterado; o padrão erra por excesso de cautela, o que é bom.Só estou dizendo que é algo que uma pessoa que está criando restrições deve sempre prestar atenção.)
A propósito, isso pode ser feito ao criar uma tabela, assim:
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
);
--Isso também funcionará.Talvez uma construção um pouco mais intuitiva?
Se você deseja criar duas colunas de tabela em um relacionamento usando uma consulta, tente o seguinte:
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)
Para criar uma chave estrangeira em qualquer tabela
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)
Como você, geralmente não crio chaves estrangeiras manualmente, mas se, por algum motivo, preciso que o script faça, por isso geralmente o criei usando o MS SQL Server Management Studio e antes de salvar as alterações, seleciono o designer de tabela | Gerar script de alteração
Este script é sobre a criação de tabelas com chave estrangeira e adicionei restrição de integridade referencial servidor 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
);
Necromante.
Na verdade, fazer isso corretamente é um pouco mais complicado.
Primeiro você precisa verificar se a chave primária existe para a coluna à qual deseja definir sua chave estrangeira para referência.
Neste exemplo, uma chave estrangeira na tabela T_ZO_SYS_Language_Forms é criada, referenciando 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