Adicionar relacionamento de chave estrangeira entre dois bancos de dados


92

Tenho duas tabelas em dois bancos de dados diferentes. Na tabela1 (no banco de dados1), existe uma coluna chamada coluna1 e é uma chave primária. Agora, na tabela2 (no banco de dados2), há uma coluna chamada coluna2 e quero adicioná-la como uma chave estrangeira.

Tentei adicioná-lo e deu-me o seguinte erro:

Msg 1763, nível 16, estado 0, linha 1
Não há suporte para referências de chave externa entre bancos de dados. Chave estrangeira Database2.table2.

Msg 1750, nível 16, estado 0, linha 1
Não foi possível criar restrição. Veja os erros anteriores.

Como faço isso, já que as tabelas estão em bancos de dados diferentes.

Respostas:


84

Você precisaria gerenciar a restrição referencial entre bancos de dados usando um Trigger.


Basicamente, você cria um gatilho de inserção e atualização para verificar a existência da chave na tabela de chave primária. Se a chave não existir, reverta a inserção ou atualização e, em seguida, trate a exceção.

Exemplo:

Create Trigger dbo.MyTableTrigger ON dbo.MyTable, After Insert, Update
As
Begin

   If NOT Exists(select PK from OtherDB.dbo.TableName where PK in (Select FK from inserted) BEGIN
      -- Handle the Referential Error Here
   END

END

Editado: Só para esclarecer. Esta não é a melhor abordagem para impor integridade referencial. O ideal é que você deseje ambas as tabelas no mesmo banco de dados, mas se isso não for possível. Então, o que está acima é uma solução potencial para você.


4
@John Hartsock - o exemplo acima pode falhar facilmente, sem adicionar o tratamento de transação apropriado. Uma discussão decente sobre o tipo de problema que pode ocorrer com "if not exists () then insert" pode ser encontrada aqui - stackoverflow.com/questions/108403/…
EBarr

17
@John Hartsock - sua solução tem uma lacuna: se um dos dois bancos de dados for restaurado a partir de um backup, os gatilhos não disparam, é claro. É assim que podemos acabar com linhas órfãs.
AK de

4
@AlexKuznetsov Exatamente. Como expliquei, esta não é a melhor abordagem, mas uma possível solução alternativa.
John Hartsock,

2
Isso é tão errado ... Eu só espero que o OP perceba que só o fato de estar pedindo algo assim, é um sintoma de que ele provavelmente está fazendo algo errado ... muito menos pensar em gatilhos ..
MeTitus

1
@Marco Como publiquei em minha resposta "Só para esclarecer. Esta não é a melhor abordagem para impor integridade referencial. Idealmente, você gostaria de ambas as tabelas no mesmo banco de dados, mas se isso não for possível. Então, o acima é uma solução potencial para vocês." Expliquei que provavelmente não era uma boa ideia.
John Hartsock

48

Se você precisar de integridade sólida como uma rocha, tenha as duas tabelas em um banco de dados e use uma restrição FK. Se sua tabela pai estiver em outro banco de dados, nada impede que alguém restaure esse banco de dados pai de um backup antigo e, então, você terá órfãos.

É por isso que FK entre bancos de dados não é compatível.


27

Na minha experiência, a melhor maneira de lidar com isso quando a fonte principal de informação autorizada para duas tabelas relacionadas tem que estar em dois bancos de dados separados é sincronizar uma cópia da tabela do local principal para o local secundário (usando T- SQL ou SSIS com verificação de erros apropriada - você não pode truncar e preencher novamente uma tabela enquanto ela tem uma referência de chave estrangeira, portanto, existem algumas maneiras de remover o problema da atualização da tabela).

Em seguida, adicione um relacionamento FK tradicional no segundo local à tabela, que é efetivamente uma cópia somente leitura.

Você pode usar um gatilho ou trabalho agendado no local principal para manter a cópia atualizada.


1
Ré. "Você pode acionar ou agendar um trabalho no local principal para manter a cópia atualizada": Por que não usar apenas a Replicação do SQL Server (especificamente o tipo Transação vs. Mesclagem desde a cópia do Assinante (a cópia que tem as Tabelas que precisam de restrições de chave estrangeira) apenas precisa ser somente leitura)? Veja: link
Tom,

@Tom sim, você certamente pode usar a replicação para manter uma cópia da tabela atualizada em um banco de dados remoto.
Cade Roux de

21

Você pode usar a restrição de verificação com uma função definida pelo usuário para fazer a verificação. É mais confiável do que um gatilho. Ele pode ser desativado e reativado quando necessário, da mesma forma que as chaves estrangeiras, e verificado novamente após uma restauração do banco de dados2.

CREATE FUNCTION dbo.fn_db2_schema2_tb_A
(@column1 INT) 
RETURNS BIT
AS
BEGIN
    DECLARE @exists bit = 0
    IF EXISTS (
      SELECT TOP 1 1 FROM DB2.SCHEMA2.tb_A 
      WHERE COLUMN_KEY_1 =  @COLUMN1
    ) BEGIN 
         SET @exists = 1 
      END;
      RETURN @exists
END
GO

ALTER TABLE db1.schema1.tb_S
  ADD CONSTRAINT CHK_S_key_col1_in_db2_schema2_tb_A
    CHECK(dbo.fn_db2_schema2_tb_A(key_col1) = 1)

1
esta é uma solução melhor do que a resposta aceita e você também pode reutilizá-la em várias tabelas
Milox

3

A resposta curta é que o SQL Server (a partir do SQL 2008) não oferece suporte a chaves estrangeiras entre bancos de dados - como afirma a mensagem de erro.

Embora você não possa ter integridade referencial declarativa (o FK), você pode atingir o mesmo objetivo usando gatilhos. É um pouco menos confiável, porque a lógica que você escreve pode ter bugs, mas levará você lá da mesma forma.

Consulte os documentos SQL @ http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx Qual estado:

Os gatilhos são frequentemente usados ​​para impor regras de negócios e integridade de dados. O SQL Server fornece integridade referencial declarativa (DRI) por meio das instruções de criação de tabela (ALTER TABLE e CREATE TABLE); entretanto, o DRI não fornece integridade referencial entre bancos de dados. Para impor integridade referencial (regras sobre os relacionamentos entre as chaves primárias e estrangeiras das tabelas), use restrições de chave primária e estrangeira (as palavras-chave PRIMARY KEY e FOREIGN KEY de ALTER TABLE e CREATE TABLE). Se existirem restrições na tabela de gatilhos, elas serão verificadas após a execução do gatilho INSTEAD OF e antes da execução AFTER do gatilho. Se as restrições forem violadas, as ações do gatilho INSTEAD OF serão revertidas e o gatilho AFTER não será executado (disparado).

Há também uma discussão OK em SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135


0

Como diz a mensagem de erro, isso não é compatível com o servidor sql. A única maneira de garantir integridade refrerencial é trabalhar com gatilhos.


1
Você pode me explicar com um exemplo
Sam
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.