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?


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

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.


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)

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
)

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?


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)

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)

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


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

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 

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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.