Цикл в триггере?

Я получил следующий сценарий,

Есть четыре таблицы COUNTRY, STATE, CITY, STREET
И у меня есть файл excel с записями выше.. возможно, 2000 строк на данный момент.

Я использовал SqlBulkCopy для импорта данных во временную таблицу, давайте назовем таблицу IMPORT.

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

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

Вышеприведенное работает, если файл Excel имеет только одну строку. После того, как я поместил исходный Excel для импорта, я понял, что следующий оператор в триггере терпит неудачу "выберите страну из INSERTED", потому что sqlbulkcopy заставляет INSERTED иметь более одной записи.

Структура таблицы

СТРАНА

  • Country_ID
  • Имя страны

ГОСУДАРСТВО

  • State_ID
  • Country_ID
  • State_Name

ГОРОД

  • City_ID
  • State_ID
  • Country_ID
  • Название города

УЛИЦА

  • Street_ID
  • City_ID
  • State_ID
  • Country_ID
  • Название улицы

ИМПОРТИРОВАТЬ

  • Имя страны
  • State_Name
  • Название города
  • Название улицы

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

Или как решить эту проблему наилучшим образом?

ПРИМЕЧАНИЕ. Поскольку они уже используют его, у меня нет контроля над структурой этих таблиц и их взаимосвязями.

Заранее спасибо.


person vijay    schedule 22.11.2010    source источник


Ответы (2)


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

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

Insert country (country_name)
select country_name 
from inserted i
where not exists 
  (select * from country c 
   where c.country_name = i.country_name)

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

person HLGEM    schedule 22.11.2010
comment
Извините за поздний ответ .. Это я искал. Спасибо, что ответили и просветили меня. - person vijay; 24.11.2010

Я бы никогда не помещал такие задачи с интенсивной обработкой в ​​триггер таблицы, используемой для массовой загрузки! И никогда никогда не начинайте добавлять циклы, такие как курсоры и тому подобное, в триггер - триггер должен быть маленьким, компактным и значимым - просто быстрая ВСТАВКА в таблицу аудита или что-то в этом роде - но он должен не поднимать тяжести!

Что вы должны сделать, так это:

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

В противном случае вы полностью лишаетесь всех преимуществ, которые имеет SqlBulkLoad.

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

person marc_s    schedule 22.11.2010