5

这是我无法解决的问题,我到处寻找。也许这里有人会知道!

我有一个名为 dandb_raw 的表,其中特别包含三列:dunsId (PK)、name 和 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.

对此最奇怪的是,触发器中的每个单独的语句都是独立工作的。如果您尝试将插入的临时表移动到其中一个中,就好像 insert 是一个一次性的表,它会感染临时表。

那么是什么导致触发器失败呢?怎么能阻止?

4

4 答案 4

2

我认为 David 和 Cervo 的结合已经解决了这里的问题。

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

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

不过仍在猜测 - 至少现在事情似乎正在发挥作用!

于 2008-09-18T19:07:23.443 回答
1

什么是company_contactInfo_updateTerritories?实际参考中提到了程序“companies_contactInfo_updateTerritories”,但我在给出的代码中没有看到它。我也看不到它在哪里被调用。除非它来自您的应用程序正在调用 SQL,因此无关紧要......

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

于 2008-09-18T18:49:47.760 回答
1

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

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

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

完成#newMatches 后,您应该删除它,以便稍后再次创建它(临时表是连接范围的!!)

DROP TABLE #newMatches
于 2008-09-18T19:04:06.137 回答
0

触发器代码(因为它必须在每次更新数据时运行)必须高效并且必须考虑多个记录插入。你第二次成功了,但第一次没有成功。您使这变得过于复杂,并且在语句中使用了诸如 Not 之类的东西,这些东西通常比使用左连接效率低。这里不需要临时表(我永远不会考虑在触发器中使用临时表),因为它们会增加触发器的效率。没有理由不写 From insert i 而不是 FROM (select dunsId, name from #magic) i

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

这里: 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

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

通常我也会避免使用 select * 但尤其是在触发器中。假设您正在插入另一个表,并且您使用 select * from some table join 以插入或删除。向该表添加一列将导致触发器失败并停止所有数据更改,直到它被修复。

您还在触发器中使用了一个函数。如果你有一个大的插入,这可能会非常缓慢。我建议您通过更新大量记录来测试这一点,看看会发生什么。所有数据更改都不会仅从用户界面发生,一次一个记录。有时会从管理工作室中的临时查询更新一个字段(当所有价格都需要调整 10% 时,这是想到的最简单的示例。)您的触发器需要能够处理这些类型,如果更新以及您期望的更新。我会运行一个更新 100000 行的测试用例,看看这个触发器减慢了多少。

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

于 2008-09-19T21:49:25.503 回答