T-SQL触发器触发"列名或者提供的值数与表定义不匹配"错误

时间:2020-03-06 14:22:44  来源:igfitidea点击:

这是我无法修复的,到处都是。也许这里有人会知道!

我有一个名为dandb_raw的表,其中特别包含三列:dunsId(PK),名称和searchName。我也有一个触发该表的触发器:

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

触发器导致插入失败:

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

出现此错误:

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.

对此最奇怪的是,触发器中的每个单独语句都可以独立工作。如果我们尝试将插入的临时表移动到其中一个表中,那么插入表似乎会感染一次性表。

那么,什么导致触发器失败呢?如何停止?

解决方案

什么是companies_contactInfo_updateTerritories?实际参考中提到过程" companies_contactInfo_updateTerritories",但在给定的代码中看不到它。我也看不到它在哪里被调用。除非是从应用程序调用SQL的,否则是无关紧要的。

如果我们测试了所有内容,并且一切正常,但是现在不起作用,那么一定有所不同。要考虑的一件事是安全性。我注意到我们仅调用表[dandb_raw]而不是[dbo]。[dandb_raw]。因此,如果用户有一个名称为[user]。[dandb_raw]的表,则该表将用于检查定义,而不是表。此外,触发器还会创建临时表。但是,如果某些临时表由于某种原因已经存在,但是具有不同的定义,则这可能也是一个问题。

我没有在代码中看到任何明显的问题。

" SELECT .. INTO"是弱功夫。尝试显式创建临时表定义:

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

完成#newMatches的处理后,我们应该摆脱它,以便以后可以再次创建它(临时表在连接范围内!!)

DROP TABLE #newMatches

我认为David和Cervo共同解决了这个问题。

我很确定发生的部分事情是我们在多个触发器中使用了#newMatches。当一个触发器更改了某些行时,它将触发另一个触发器,该触发器将尝试使用范围为#newMatches的连接。

结果,它将尝试查找具有不同模式的已存在的表,然后终止并产生上述消息。一个有利的证据:插入是否使用堆栈样式范围(嵌套触发器有自己的插入?)

仍在猜测,至少现在看来一切正常!

触发代码(因为它必须在每次更新数据时都必须运行)必须高效并且必须考虑多次记录插入。我们在第二个成功,但没有成功。我们已使其变得过于复杂,并使用了诸如Not语句之类的方法,这些语句通常比使用左联接的efficeint效率低。临时表在这里是不必要的(我永远不会考虑在触发器中使用一个),因为它们会增加触发器的效率。没有理由不写
从插入我
代替
FROM(从#magic中选择dunsId,名称)i

第一个可能会更快,并且更易于阅读和维护。

这里:
JOIN(选择大小写,当charindex('/',url)<> 0时再离开(url,charindex('/',url)-1)否则url结尾urlMatch,*来自公司)c ON dandb.url = c.urlMatch

我们正在选择表中的所有字段,即使我们似乎只使用其中一个。为什么?我们也正在公司的所有记录上运行该案例,即使我们加入后可能并不需要所有这些记录。

同样,通常我会避免使用select *,但尤其是在触发器中。假设我们要插入另一个表,并且我们使用了从某些表中选择select *的方法来联接插入或者删除。在该表中添加一列将导致触发器失败并停止所有数据更改,直到修复该问题为止。

我们还在触发器中使用了一个函数。如果插入量较大,该速度会非常缓慢。我建议我们通过更新大量记录来进行测试,然后看看会发生什么。并非仅通过用户界面一次就完成一条记录,所有的数据更改都不会发生。有时候,会从Management Studio中的一个临时查询中更新一个字段(当我们想到的所有最简单的示例时,所有价格都需要调整10%。)如果更新以及我们期望的更新。我将运行一个测试案例来更新100000行,并查看此触发器在多大程度上减慢了速度。

也许这并不能真正回答问题,但是触发因素远非最佳,我不得不说。