Sql Server INSERT проблема области видимости - PullRequest
0 голосов
/ 12 марта 2009

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

Возьмите следующий фрагмент SQL:

declare @source table (id int)
declare @target table(id int primary key, sourceId int)


set nocount on

insert into @target values (0,0)

insert into @source(id) values(1)
--insert into @source(id) values(2)

set nocount off

insert into @target select (select max(id)+1 from @target), s.id from @source s

select * from @target

Это, очевидно, выполняется без ошибок, но теперь раскомментируйте вторую строку вставки и возникает следующая ошибка:

Msg 2627, Level 14, State 1, Line 15
Violation of PRIMARY KEY constraint 'PK__#7DB3CB72__7EA7EFAB'. Cannot insert duplicate key in object 'dbo.@target'.

Я понимаю, что оператор вставки более чем вероятен в отношении снимка таблицы @target, поэтому (select max(id)+1 from @target) всегда будет возвращать значение 1, вызывая ошибку нарушения выше ...

Есть ли способ обойти это, кроме обращения к курсору?

Ответы [ 3 ]

1 голос
/ 12 марта 2009

Измените свой оператор вставки следующим образом:

вставить в @target select (выберите max (id) из @target) + (ROW_NUMBER () OVER (ЗАКАЗАТЬ s.id)), s.id от @source s

Это должно сработать для этого конкретного случая, но я бы осторожно обобщил его.

1 голос
/ 12 марта 2009

Вы можете использовать столбец идентификаторов (это именно то, для чего они предназначены)

declare @target table(id int IDENTITY(1,1), sourceId int)

Если ваша проблема заключается в том, что предложение select "вычисляется" до выполнения вставки, то нет никакого способа обойти это, используя один запрос SQL

Я думаю, что это дизайн; Для вставки, чтобы избежать дубликатов, идентификатор индекса должен быть вычислен во время вставки, а не во время выбора. Это точное назначение ключевого слова IDENTITY.

Если вы хотите вставить один выбор за раз, вы должны написать отдельные запросы (например, с использованием курсоров, но вы потеряете атомарность и должны будете использовать правильные ключевые слова блокировки, чтобы избежать условий гонки)

0 голосов
/ 12 марта 2009

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

Почему бы вам просто не использовать столбец идентификаторов и позволить базе данных обрабатывать назначение нового первичного идентификатора?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...