Como crio uma chave estrangeira no SQL Server?

243

Eu nunca codifiquei manualmente o código de criação de objeto para o SQL Server e a decodificação de chave estrangeira é aparentemente diferente entre o SQL Server e o Postgres. Aqui está o 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 O número de colunas de referência na chave estrangeira difere do número de colunas referenciadas, tabela 'question_bank'.

Você consegue identificar o erro?

mmattax
fonte
2
Para sua informação, sempre é melhor nomear suas restrições, especialmente com ORMs em uso.
precisa

Respostas:

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
fonte
37
Também pode ser útil nomear a restrição de chave estrangeira. Isso ajuda na solução de violações de fk. Por exemplo: "chave estrangeira fk_questionbank_exams (question_exam_id) faz referência a exames (exam_id)"
John Vasileff 07/09/08
31
Eu concordo nomeando restrições é um plano bom, mas, no SQL Server 2008 R2, pelo menos, a sintaxe da última linha tem que ser "restrição fk_questionbank_exams chave estrangeira (question_exam_id) referências exames (exam_id)"
Jonathan Sayce
5
Um ponto muito importante a ser observado é que a criação da chave estrangeira não cria um índice. A associação de outra tabela a esta pode resultar em uma consulta extremamente lenta.
Rocklan 5/09/14
Não sei ao certo por que é diferente, mas tive que fazer CONSTRAINT fk_questionbank_exams CHAVE ESTRANGEIRA (question_exam_id) exames de REFERÊNCIAS (exam_id)
tenmiles
É necessário escrever um NON NULL para a chave primária, ou isso é explícito quando escrevemos a restrição de chave primária para a coluna, por exemplo, eu sento o suficiente para denotar uma coluna como chave primária para ter uma restrição não nula ou devo NON NULL seja especificado, ou seja, escrito explicitamente?
Gary
326

E se você quiser criar a restrição por conta própria, poderá 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 em linha, apenas porque prefiro nomear minhas próprias restrições.

AlexCuse
fonte
19
Eu sei que isso é velho demais ... mas cheguei aqui a partir de uma pesquisa no google e muitos outros poderiam. Apenas uma solução rápida: a maneira correta de fazer referência é: REFERÊNCIAS MyOtherTable (MyOtherIDColumn)
PedroC88
3
MyTable_MyColumn_FK é a melhor prática de nomeação.
shaijut 4/06/19
70

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)
Sara Chipps
fonte
1
Ao usar um ORM, é útil ter restrições nomeadas com várias referências à tabela estrangeira ... Utilizadas restrições nomeadas nas propriedades com EF4, para que eu soubesse qual entrada da tabela de contatos era para comprador, vendedor, etc.
Tracker1
31

Eu gosto da resposta de AlexCuse, mas algo que você deve prestar atenção sempre que adicionar uma restrição de chave estrangeira é como deseja que as atualizações da coluna referenciada em uma linha da tabela referenciada sejam tratadas e, principalmente, como deseja excluir exclusões de linhas na referenciada 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)

.. as atualizações ou exclusões na tabela referenciada explodem com 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.

Se você o criar assim:

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

..as atualizações e exclusões na tabela pai resultarão em atualizações e exclusões das linhas correspondentes na tabela de referência.

(Eu não estou sugerindo que o padrão deva ser alterado, o padrão erra por precaução, o que é bom. Só estou dizendo que é algo que uma pessoa que está criando constaints deve sempre prestar atenção .)

Isso pode ser feito, a propósito, 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
)
Shavais
fonte
Funciona melhor com "alterar tabela 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
);

- Isso também funcionará. Talvez uma construção um pouco mais intuitiva?

Bijimon
fonte
1
É isso que eu faço, mas tenho uma pergunta: há algum ponto em adicionar as palavras-chave "chave estrangeira"? - Parece que funciona sem que, por exemplo: question_exam_id uniqueidentifier não nulos exames referências (exam_id)
JSideris
As palavras-chave "Chave estrangeira" são opcionais. Na minha opinião, torna o código mais legível.
Bijimon 30/07/2014
8

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

Se você deseja criar duas colunas da 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)
Md Ashikul Islam
fonte
5

Como você, normalmente não crio chaves estrangeiras manualmente, mas se por algum motivo eu precisar do script, normalmente o crio usando o ms sql server management studio e antes de salvar e depois as alterações, seleciono Table Designer | Gerar script de alteração

Vitor Silva
fonte
4

Este script é sobre a criação de tabelas com chave estrangeira e eu adicionei restrição de integridade referencial 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
fonte
3

Necromante.
Na verdade, fazer isso corretamente é um pouco mais complicado.

Você primeiro precisa verificar se a chave primária existe para a coluna à qual você deseja definir sua chave estrangeira.

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 
Stefan Steiger
fonte
2

Eu sempre uso essa sintaxe para criar a restrição de chave estrangeira entre 2 tabelas

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

ie

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