T-SQL déclenche le déclenchement d'un & # 8220; Le nom de colonne ou le nombre de valeurs fournies ne correspond pas à la définition de la table & # 8221; Erreur

StackOverflow https://stackoverflow.com/questions/95218

  •  01-07-2019
  •  | 
  •  

Question

Voici quelque chose que je n'ai pas pu résoudre et que j'ai regardé partout . Peut-être que quelqu'un ici saura!

J'ai une table appelée dandb_raw, avec trois colonnes en particulier: dunsId (PK), name et searchName. J'ai aussi un déclencheur qui agit sur cette table:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dandb_raw_searchNames]
    ON [dandb_raw]
    FOR INSERT, UPDATE
    AS

SET NOCOUNT ON

  select dunsId, name into #magic from inserted

        UPDATE dandb
            SET dandb.searchName = company_generateSearchName(dandb.name)
            FROM (select dunsId, name from #magic) i
            INNER JOIN dandb_raw dandb
                on i.dunsId = dandb.dunsId


        --Add new search matches
        SELECT c.companyId, dandb.dunsId
            INTO #newMatches
            FROM dandb_raw dandb
            INNER JOIN (select dunsId, name from #magic) a
                on a.dunsId = dandb.dunsId
            INNER JOIN companies c
                ON dandb.searchName = c.searchBrand
                --avoid url matches that are potentially wrong
                AND (lower(dandb.url) = lower(c.url)
                    OR dandb.url = ''
                    OR c.url = ''
                    OR c.url is null)


        INSERT INTO #newMatches (companyId, dunsId)
        SELECT c.companyId, max(dandb.dunsId) dunsId
            FROM dandb_raw dandb
            INNER JOIN
                (
                    select
                    case when charindex('/',url) <> 0 then left(url, charindex('/',url)-1)
                    else url
                    end urlMatch, * from companies
                ) c
                ON dandb.url = c.urlMatch
            where subsidiaryOf = 1 and isReported = 1 and dandb.url <> ''
                and c.companyId not in (select companyId from #newMatches)
            group by companyId
            having count(dandb.dunsId) = 1

        UPDATE cd
            SET cd.dunsId = nm.dunsId
            FROM companies_dandb cd
            INNER JOIN #newMatches nm
                ON cd.companyId = nm.companyId
GO

Le déclencheur provoque l'échec des insertions:

insert into  [dandb_raw](dunsId, name)
    select 3442355, 'harper'
    union all
    select 34425355, 'har 466per'
update [dandb_raw] set name ='grap6767e'

Avec cette erreur:

Msg 213, Level 16, State 1, Procedure companies_contactInfo_updateTerritories, Line 20
Insert Error: Column name or number of supplied values does not match table definition.

La chose la plus curieuse à ce sujet est que chacune des déclarations individuelles dans le déclencheur fonctionne toute seule. C'est presque comme si inséré est une table unique infectant les tables temporaires si vous essayez de déplacer inséré dans l'un d'eux.

Alors, qu'est-ce qui cause l'échec du déclencheur? Comment peut-il être arrêté?

Était-ce utile?

La solution

Je pense que David et Cervo ont résolu le problème ici.

Je suis à peu près sûr qu'une partie de ce qui se passait était que nous utilisions #newMatches dans plusieurs déclencheurs. Lorsqu'un déclencheur modifie certaines lignes, il déclenche un autre déclencheur, qui tente d'utiliser la connexion étendue #NewMatches.

Par conséquent, il essaierait de trouver la table déjà existante avec un schéma différent, de mourir et de produire le message ci-dessus. Un élément de preuve qui serait en faveur: l’insertion utilise-t-elle une portée de style pile (les déclencheurs imbriqués ont leurs propres insérés?)

Toujours en train de spéculer - au moins, les choses semblent fonctionner maintenant!

Autres conseils

Qu'est-ce que companies_contactInfo_updateTerritories? La procédure de référence actuelle mentionne "companies_contactInfo_updateTerritories". mais je ne le vois pas dans le code donné. Aussi, je ne vois pas où il est appelé. À moins que ce ne soit de votre application qui appelle le code SQL et donc non pertinente ....

Si vous avez tout testé et que cela a fonctionné mais que maintenant cela ne fonctionne plus, alors quelque chose doit être différent. Une chose à considérer est la sécurité. J'ai remarqué que vous appelez simplement la table [dandb_raw] et non pas [dbo]. [Dandb_raw]. Donc, si l'utilisateur avait une table du même nom [utilisateur]. [Dandb_raw], cette table serait utilisée pour vérifier les définitions à la place de votre table. En outre, le déclencheur crée des tables temporaires. Mais si certaines des tables temporaires existaient déjà pour une raison quelconque, mais avec des définitions différentes, cela pourrait également poser problème.

Je ne vois pas de problème évident dans le code.

"SELECT .. INTO" est le kung-fu faible. Essayez de créer explicitement la définition de la table temporaire:

CREATE TABLE #newMatches
(
  CompanyID int PRIMARY KEY,
  DunsID int
)

Quand vous avez fini avec #newMatches, vous devriez vous en débarrasser pour pouvoir le recréer plus tard (les tables temporaires sont connectées !!)

DROP TABLE #newMatches

Le code de déclenchement (car il doit être exécuté à chaque fois que les données sont mises à jour) doit être efficace et doit prendre en compte plusieurs insertions d'enregistrement. Vous avez réussi à la seconde mais pas la première. Vous avez rendu cela trop compliqué et avez utilisé des choses telles que Non dans des déclarations qui sont généralement moins efficaces que d'utiliser une jointure gauche. Les tables temporaires sont inutiles ici (je n'envisagerais jamais d'en utiliser une dans un déclencheur) car elles ajoutent à l'inefficacité du déclencheur. Il n'y a pas de raison de ne pas écrire D'inséré i au lieu de  FROM (sélectionnez dunsId, nom from #magic) i

Le premier est susceptible d’être plus rapide et plus simple à lire et à maintenir.

ici: JOIN (sélectionnez la casse lorsque charindex ('/', url) < > 0 puis à gauche (url, charindex ('/', url) -1), sinon url end urlMatch, * des entreprises) c ON dandb.url = c .urlMatch

Vous sélectionnez tous les champs de la table, même si vous semblez n'en utiliser qu'un seul. Pourquoi? Vous utilisez également ce cas sur tous les enregistrements de la société même si, après votre inscription, vous n’avez peut-être plus besoin de tous.

De manière générale, j’éviterais d’utiliser select *, mais surtout dans un déclencheur. Supposons que vous insérez dans une autre table et que vous utilisiez select * dans une table jointe à insérée ou supprimée. L'ajout d'une colonne à cette table entraînerait l'échec du déclencheur et arrêterait toutes les modifications de données jusqu'à ce qu'il soit corrigé.

Vous avez également utilisé une fonction dans le déclencheur. Cela peut être douloureusement lent si vous avez un gros insert. Je vous suggère de tester cela en mettant à jour un grand groupe d'enregistrements et de voir ce qui se passe. Toutes les modifications de données ne se produisent pas uniquement à partir de l'interface utilisateur, enregistrement par enregistrement. Il y aura des cas où un champ est mis à jour à partir d'une requête ad hoc dans studio de gestion (lorsque tous les prix doivent être ajustés de 10%, ce qui nous vient à l'esprit.) Votre déclencheur doit pouvoir gérer ces types si mises à jour ainsi que celles que vous attendez. Je voudrais exécuter un scénario de test mettant à jour 100 000 lignes et voir à quel point ce déclencheur ralentit les choses.

Peut-être que cela ne répond pas vraiment à votre problème, mais le déclencheur est tellement loin d’être optimal, je devais le dire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top