Добавить отношения внешнего ключа между двумя базами данных

У меня две таблицы в двух разных базах данных. В таблице table1 (в базе данных 1) есть столбец с именем column1, который является первичным ключом. Теперь в table2 (в базе данных2) есть столбец с именем column2, и я хочу добавить его в качестве внешнего ключа.

Я попытался добавить его, и это дало мне следующую ошибку:

Msg 1763, уровень 16, состояние 0, строка 1
Ссылки на внешние ключи между базами данных не поддерживаются. Внешний ключ Database2.table2.

Msg 1750, уровень 16, состояние 0, строка 1
Не удалось создать ограничение. См. Предыдущие ошибки.

Как мне это сделать, поскольку таблицы находятся в разных базах данных.


person Sam    schedule 15.12.2010    source источник


Ответы (6)


Вам нужно будет управлять ссылочным ограничением в базах данных с помощью триггера.


Обычно вы создаете триггер вставки, обновления, чтобы проверить наличие ключа в таблице первичных ключей. Если ключ не существует, отмените вставку или обновление, а затем обработайте исключение.

Пример:

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

Отредактировано: просто для пояснения. Это не лучший подход к обеспечению ссылочной целостности. В идеале вам нужно, чтобы обе таблицы были в одной базе данных, но если это невозможно. Тогда приведенное выше - это потенциальная работа для вас.

person John Hartsock    schedule 15.12.2010
comment
Вы можете объяснить мне на примере - person Sam; 15.12.2010
comment
Точно так же мне нужно создать триггер обновления. - person Sam; 15.12.2010
comment
@Sam Да ... но вы можете создать один триггер как для вставки, так и для обновления. См. Мой отредактированный ответ - person John Hartsock; 15.12.2010
comment
ТАК Этот триггер должен быть создан в таблице, куда я хочу добавить права внешнего ключа - person Sam; 15.12.2010
comment
@John Hartsock - приведенный выше пример может легко потерпеть неудачу без добавления соответствующей обработки транзакции. Приличное обсуждение типа проблемы, которая может возникнуть с if not exists () then insert, можно найти здесь - stackoverflow.com/questions/108403/ - person EBarr; 15.12.2010
comment
@EBarr .. Понятно. Это явно не лучший способ справиться с ограничениями по ссылкам. Я просто пытался дать некоторое представление - person John Hartsock; 15.12.2010
comment
@John Hartsock - в вашем решении есть лазейка: если одна из двух баз данных восстанавливается из резервной копии, триггеры, конечно, не срабатывают. Вот как мы можем получить сиротские строки. - person A-K; 22.03.2011
comment
@AlexKuznetsov Именно. Как я объяснил, это не лучший подход, но его можно обойти. - person John Hartsock; 22.03.2011
comment
Это так неправильно ... Я просто надеюсь, что ОП понимает, что сам факт того, что он просит о чем-то вроде этого, является признаком того, что он, скорее всего, делает что-то не так ... не говоря уже о триггерах ... - person MeTitus; 18.05.2014
comment
@Marco, как я написал в своем ответе Просто для пояснения. Это не лучший подход к обеспечению ссылочной целостности. В идеале вам нужно, чтобы обе таблицы были в одной базе данных, но если это невозможно. Тогда приведенное выше - это потенциальная работа для вас. Я объяснил, что это, вероятно, не очень хорошая идея. - person John Hartsock; 19.05.2014
comment
@JohnHartsock достаточно честно. - person MeTitus; 19.05.2014

Если вам нужна надежная целостность, поместите обе таблицы в одну базу данных и используйте ограничение FK. Если ваша родительская таблица находится в другой базе данных, ничто не мешает кому-либо восстановить эту родительскую базу данных из старой резервной копии, и тогда у вас останутся сироты.

Вот почему FK между базами данных не поддерживается.

person A-K    schedule 15.12.2010

По моему опыту, лучший способ справиться с этим, когда основной авторитетный источник информации для двух связанных таблиц должен находиться в двух отдельных базах данных, - это синхронизировать копию таблицы из основного расположения во вторичное расположение (используя T- SQL или SSIS с соответствующей проверкой ошибок - вы не можете усечь и повторно заполнить таблицу, пока она имеет ссылку на внешний ключ, поэтому есть несколько способов избавиться от кошки при обновлении таблицы).

Затем добавьте традиционную связь FK во втором месте таблицы, которая фактически является копией только для чтения.

Вы можете использовать триггер или запланированное задание в основном расположении, чтобы обновлять копию.

person Cade Roux    schedule 15.12.2010
comment
Re. Вы можете запустить или запланировать задание в основном расположении, чтобы обновлять копию: почему бы просто не использовать репликацию SQL Server (в частности, тип транзакции или слияния, поскольку копия подписчика (копия, которая имеет таблицы, требующие ограничений внешнего ключа) просто должна быть быть только для чтения)? См .: ссылка - person Tom; 20.04.2017
comment
@Tom да, вы, безусловно, можете использовать репликацию, чтобы обновлять копию таблицы в удаленной базе данных. - person Cade Roux; 20.04.2017

Вы можете использовать ограничение проверки с функцией, определяемой пользователем, чтобы выполнить проверку. Он надежнее спускового крючка. Его можно отключить и снова включить при необходимости так же, как и внешние ключи, и перепроверить после восстановления базы данных2.

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)
person Camilo J    schedule 11.11.2015
comment
это лучшее решение, чем принятый ответ, и вы также можете повторно использовать его в нескольких таблицах - person Milox; 21.02.2019

Короткий ответ заключается в том, что SQL Server (начиная с SQL 2008) не поддерживает внешние ключи между базами данных, как указано в сообщении об ошибке.

Хотя у вас не может быть декларативной ссылочной целостности (FK), вы можете достичь той же цели с помощью триггеров. Это немного менее надежно, потому что в написанной вами логике могут быть ошибки, но она все равно приведет вас туда.

См. Документы SQL @ http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx Какое состояние:

Триггеры часто используются для обеспечения соблюдения бизнес-правил и обеспечения целостности данных. SQL Server обеспечивает декларативную ссылочную целостность (DRI) с помощью операторов создания таблиц (ALTER TABLE и CREATE TABLE); однако DRI не обеспечивает ссылочной целостности между базами данных. Чтобы обеспечить ссылочную целостность (правила отношений между первичным и внешним ключами таблиц), используйте ограничения первичного и внешнего ключей (ключевые слова PRIMARY KEY и FOREIGN KEY команд ALTER TABLE и CREATE TABLE). Если ограничения существуют в таблице триггеров, они проверяются после выполнения триггера INSTEAD OF и до выполнения триггера AFTER. Если ограничения нарушаются, действия триггера INSTEAD OF откатываются, а триггер AFTER не выполняется (запускается).

В SQLTeam также есть нормальное обсуждение - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135

person EBarr    schedule 15.12.2010

Как говорится в сообщении об ошибке, это не поддерживается на сервере sql. Единственный способ обеспечить референциальную целостность - работать с триггерами.

person Jan    schedule 15.12.2010
comment
Вы можете объяснить мне на примере - person Sam; 15.12.2010