Как исправить эту проблему с хранимой процедурой

У меня 2 стола. Ниже приведены лишь урезанные версии этих таблиц.

TableA
Id <pk> incrementing
Name varchar(50)

TableB
TableAId <pk> non incrementing
Name varchar(50)

Теперь эти таблицы связаны друг с другом.

Сценарий

Пользователь 1 заходит на мой сайт и выполняет некоторые действия (в данном случае добавляет строки в таблицу A). Поэтому я использую SqlBulkCopy все эти данные в таблице A.

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

Поэтому я думаю о хранимой процедуре, которая находит все идентификаторы, которых нет в таблице B, а затем вставляет их.

INSERT INTO TableB (TableAId , Name)
SELECT Id,Name FROM TableA as tableA
WHERE not exists( ...)

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

Итак, есть ли лучший способ работы с двумя таблицами, которые необходимо обновить при использовании массовой вставки?


person chobo2    schedule 12.08.2010    source источник
comment
Я почти уверен, что весь смысл RDMS заключается в том, чтобы избежать проблем с взаимным исключением и обновлением при наличии нескольких одновременных подключений. Я не эксперт по БД и не играю по телевизору, но, насколько мне известно, есть конструкции, которые вы можете использовать, чтобы сделать запрос атомарным.   -  person San Jacinto    schedule 12.08.2010
comment
@San Jacinto: правильно, но SQLBulkCopy - это сложность. Даже в этом случае более поздние записи не могут отличить, какие строки принадлежат им, а какие из предыдущих записей с пробелами в B.   -  person gbn    schedule 12.08.2010


Ответы (3)


SQLBulkCopy усложняет это, поэтому я бы рассмотрел возможность использования промежуточной таблицы и предложение OUTPUT

Пример в смеси клиентского псевдокода и SQL

create SQLConnection

Create #temptable
Bulkcopy to #temptable

Call proc on same SQLConnection

proc:
   INSERT tableA (..)
   OUTPUT INSERTED.key, .. INTO TableB
   SELECT .. FROM #temptable

close connection

Примечания:

  • temptable будет локальным для соединения и будет изолированным

  • записи в A и B будут атомарными
  • перекрывающиеся или более поздние записи не заботятся о том, что происходит позже с A и B
  • подчеркивая последний пункт, A и B будут заполняться только из набора строк в #temptable

Альтернатива:

Добавьте еще один столбец в A и B с именем sessionid и используйте его для идентификации пакетов строк.

person gbn    schedule 12.08.2010

Одним из вариантов может быть использование предложения вывода SQL Servers:

INSERT YourTable (name)
OUTPUT INSERTED.*
VALUES ('NewName')

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

person Andomar    schedule 12.08.2010

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

person mat-mcloughlin    schedule 12.08.2010
comment
Просто, но вам нужно указать [триггеры срабатывания]][msdn.microsoft.com/en-us/library/, для которого могут потребоваться права DDL - person gbn; 13.08.2010