Faire une boucle dans Trigger?

sqlbulkcopy sql-server-2008 triggers

Question

J'ai eu ce scénario suivant,

Il y a quatre tables PAYS, ÉTAT, VILLE, RUE
Et j'ai le fichier Excel avec les enregistrements de ce qui précède ... éventuellement 2000 lignes.

J'ai utilisé SqlBulkCopy pour importer les données dans une table temporaire. Nommez la table IMPORT.

Et j’ai écrit un déclencheur pour l’insertion sur la table IMPORT qui obtient l’enregistrement inséré et divise le pays, l’état, la ville et la rue, puis les insère dans la table respective.

Dans ce déclencheur, je dois effectuer une vérification conditionnelle, par exemple, si le nom du pays est déjà présent, il renvoie alors le COUNTRY_ID, puis l'insère et obtient le nouveau COUNTRY_ID.

Ce qui précède fonctionne si le fichier Excel ne comporte qu'une seule ligne. Une fois que j'ai mis l'excel d'origine pour l'importation, j'ai compris que l'instruction suivante dans le déclencheur échouait: "sélection du pays dans INSERTED" car sqlbulkcopy rend INSERTED à plusieurs enregistrements.

Structure de la table

PAYS

  • Country_ID
  • Nom du pays

ETAT

  • State_ID
  • Country_ID
  • Nom d'état

VILLE

  • City_ID
  • State_ID
  • Country_ID
  • Nom de Ville

RUE

  • Street_ID
  • City_ID
  • State_ID
  • Country_ID
  • Nom de rue

IMPORTER

  • Nom du pays
  • Nom d'état
  • Nom de Ville
  • Nom de rue

Donc, puis-je avoir une déclaration de boucle dans le déclencheur qui va parcourir tous les enregistrements insérés?

Ou comment aborder cela de la meilleure façon?

NOTE: Comme ils l'utilisent déjà, je n'ai aucun contrôle sur la structure de la table et leurs relations.

Merci d'avance.

Réponse acceptée

Votre premier problème est que vous ne devriez jamais envisager de faire une boucle sur un jeu d’enregistrements comme premier choix. C'est presque toujours le mauvais choix comme c'est le cas ici. Votre prochain problème est que les déclencheurs traitent l’ensemble des enregistrements pas un à la fois et, à partir de votre description, je parie que vous l’avez écrit en supposant qu’il traiterait un enregistrement à la fois. Vous avez besoin d'un processus basé sur les ensembles.

Il est probable que vous avez besoin de quelque chose comme ceci dans votre déclencheur qui insère tous les pays insérés qui ne sont pas déjà dans la table des pays (ceci suppose que country_Id est une colonne d’identité entière):

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

Vous pouvez également utiliser un proc stocké au lieu d'un déclencheur pour l'insérer dans les vraies tables à partir de la table intermédiaire.


Réponse populaire

Je ne mettrais jamais une telle tâche intensive de traitement dans un déclencheur d'une table utilisée pour un chargement en bloc! Et ne commencez jamais à insérer des boucles telles que des curseurs et des éléments similaires dans un déclencheur - un déclencheur doit être petit, maigre et méchant - juste un INSERT rapide dans une table d’audit ou quelque chose du genre - mais cela ne devrait pas faire de gros travail!

Ce que vous devriez faire est ceci:

  • utilisez SqlBulkLoad pour SqlBulkLoad vos données dans cette table de transfert le plus rapidement possible, sans déclencher quoi que ce soit
  • puis en fonction de cette table intermédiaire, effectuez le post-traitement nécessaire en fractionnant les valeurs de colonne et ainsi de suite.

Sinon, vous tuez totalement les avantages de SqlBulkLoad .

Et pour effectuer ce post-traitement (comme déterminer Country_ID pour un Country donné), vous n'avez besoin d'aucun curseur ni d'aucun de ces éléments pervers. Utilisez simplement des instructions UPDATE standard et standard, sur votre table. avoir besoin.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi