Нет способа использовать вывод TSQL с обычными ограничениями внешнего ключа? - PullRequest
6 голосов
/ 27 июля 2010

Следующий фрагмент кода завершается с ошибкой:

Таблица назначения dbo.forn предложения OUTPUT INTO не может находиться ни с одной стороны отношения (первичный ключ, внешний ключ).Обнаружено ссылочное ограничение 'FK_forn_prim'. "

Я могу использовать вывод только путем отключения ограничений внешнего ключа? Как это можно сделать?

IF OBJECT_ID ('dbo.forn') IS NOT NULL
begin
    alter table dbo.forn drop constraint FK_forn_prim
    DROP TABLE dbo.forn;
end
IF OBJECT_ID ('dbo.prim') IS NOT NULL
    DROP TABLE dbo.prim;
go

CREATE TABLE dbo.prim (c1 int PRIMARY KEY);
CREATE TABLE dbo.forn (c1 int CONSTRAINT FK_forn_prim FOREIGN KEY (c1) REFERENCES dbo.prim(c1));
go

INSERT INTO dbo.prim
    OUTPUT inserted.c1 INTO dbo.forn
SELECT 1;

Ответы [ 4 ]

13 голосов
/ 28 июля 2010

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

2 голосов
/ 06 августа 2012

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

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

ALTER TABLE dbo.forn
NOCHECK CONSTRAINT FK_forn_prim
GO

INSERT INTO dbo.prim
    OUTPUT inserted.c1 INTO dbo.forn
SELECT 1;

ALTER TABLE dbo.forn
CHECK CONSTRAINT FK_forn_prim
GO
2 голосов
/ 27 июля 2010

Согласно technet

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

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

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

1 голос
/ 18 марта 2015

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

( ЭТО НЕ РЕКОМЕНДУЕТСЯ. См. Обновление ниже)

Однако я обнаружил, что это ограничение подрывается, если ограничение внешнего ключа отключено и повторно включено с помощью NOCHECK/CHECK даже после повторного включения ограничения . Другими словами: одного цикла отключения-включения достаточно, чтобы сделать ограничение FK «невидимым» для запрета «вывод в внешний ключ». Обратите внимание на модификацию ниже:

IF OBJECT_ID ('dbo.forn') IS NOT NULL
begin
    alter table dbo.forn drop constraint FK_forn_prim
    DROP TABLE dbo.forn;
end
IF OBJECT_ID ('dbo.prim') IS NOT NULL
    DROP TABLE dbo.prim;
go

CREATE TABLE dbo.prim (c1 int PRIMARY KEY);
-- note change here:
CREATE TABLE dbo.forn (c1 int );
alter TABLE dbo.forn with nocheck add CONSTRAINT FK_forn_prim FOREIGN KEY (c1)     REFERENCES dbo.prim(c1);
alter TABLE dbo.forn check CONSTRAINT FK_forn_prim ;
-- end change
go

INSERT INTO dbo.prim
    OUTPUT inserted.c1 INTO dbo.forn
select 1;

Следующая ошибка (нарушение ограничения), так что вы знаете, что DRI все еще работает:

INSERT INTO dbo.prim
    OUTPUT inserted.c1 + 1 INTO dbo.forn
select 2;

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

UPDATE

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

В результате: alter TABLE dbo.forn check CONSTRAINT FK_forn_prim ; повторно включает ограничение, но оставляет его в «недоверенном» состоянии, поэтому оно не может быть полностью использовано механизмом SQL для оптимизации индекса и тому подобного. Не рекомендуется Правильный способ повторного включения -

alter table dbo.forn with check check CONSTRAINT FK_forn_prim;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...