Цикл в триггере? - PullRequest
       14

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

0 голосов
/ 22 ноября 2010

У меня следующий сценарий,

Есть четыре таблицы СТРАНА, ГОСУДАРСТВО, ГОРОД, УЛИЦА
И у меня есть файл Excel с записями выше ... возможно 2000 строк на данный момент.

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

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

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

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

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

СТРАНА

  • Country_ID
  • COUNTRY_NAME

STATE

  • State_ID
  • Country_ID
  • State_Name

ГОРОД

  • City_ID
  • State_ID
  • COUNTRY_ID

STREET

  • Street_ID
  • CITY_ID
  • State_ID
  • COUNTRY_ID
  • STREET_NAME

ИМПОРТ

  • COUNTRY_NAME
  • State_Name
  • city_name
  • STREET_NAME

Так можно ли в цикле использовать оператор цикла, который будет перебирать все записи в INSERTED?

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

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

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

Ответы [ 2 ]

2 голосов
/ 22 ноября 2010

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

Вероятно, вам нужно что-то подобное в вашем триггере, которое вставит все страны во вставке, которых еще нет в таблице стран (предполагается, что 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)

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

1 голос
/ 22 ноября 2010

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

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

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

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

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

...