触发器的奇怪行为

时间:2013-02-14 19:09:46

标签: sql-server triggers ssis

我有一个触发器(SQL 2008 R2)执行一个简单的操作,但结果不合逻辑。 以下是概述:

文本文件被送到SSIS包,其中包含一行(一条记录),将其加载到“ORDERS_IN_PROCESS”表中。数据访问模式在“OLE DB目标”中设置为“表或视图”,以允许触发触发。

这是我的ORDERS表:

OrderID        ItemNo
---------    ---------
9813           1
9813           2
9813           3
9817           1

所以,SSIS执行和 ORDERS_IN_PROCESS获取一个插入的记录,即OrderID 9813

触发了触发器:

INSERT INTO ORDERS_ARCHIVE SELECT * FROM ORDERS WHERE OrderID=INSERTED.OrderID

到目前为止非常简单......

我在ORDERS_ARCHIVE(与ORDERS相同的布局)表中得到的结果是

OrderId       ItemNo
---------   ----------
9813          3

2个订单项的其余部分在哪里?

注意,它只将从ORDERS表中读取的最后一行插入到ORDERS_ARCHIVE中。

我需要ORDERS_ARCHIVE中的所有3个。

为什么会这样?

我认为它与SSIS使用“OLE DB Destination”处理它的方式有关,因为如果我手动将记录插入到RLFL中,触发器就会完全按照它应该执行的操作并从BACK插入所有3条记录。 / p>

你可能会说每次触发器触发一次,我同意,但在这种情况下,我只有一批记录。

我正在考虑一个sp,但我宁愿不为那些如此微不足道的东西增加另一层次的复杂性。

有什么想法吗?

感谢。

2 个答案:

答案 0 :(得分:5)

我认为这根本不与SSIS有关,而是与你的触发器有关。您可以在查询中使用IN,而不是JOIN

INSERT INTO ORDERS_ARCHIVE 
SELECT O.* 
FROM ORDERS O
INNER JOIN INSERTED I
     ON O.ORderID = I.OrderID

答案 1 :(得分:2)

我同意Lamark,故意拼写错误,对你的触发器的评估是不正确的。

您为触发器提供的逻辑无法编译。 WHERE子句无效。我假设,正如Lamak所做的那样,你的意图是基于OrderID加入。

create table dbo.ORDERS_ARCHIVE
(
    OrderID int
,   ItemNo int
)
GO
create table dbo.ORDERS
(
    OrderID int
,   ItemNo int
)
GO
create trigger 
    trUpdate
ON
    dbo.ORDERS
    AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;
    -- This doesn't work
    -- Msg 4104, Level 16, State 1, Procedure trUpdate, Line 12
    -- The multi-part identifier "INSERTED.OrderID" could not be bound.
    --INSERT INTO dbo.ORDERS_ARCHIVE 
    --SELECT * 
    --FROM ORDERS 
    --WHERE OrderID=INSERTED.OrderID;

    -- I think you meant
    INSERT INTO dbo.ORDERS_ARCHIVE 
    SELECT * 
    FROM ORDERS 
    WHERE OrderID=(SELECT INSERTED.OrderID FROM INSERTED);
 END
 GO

然后我开始编写一个简单的SSIS包,我有一个数据源,提供您指定的4行并写入dbo.ORDERS.我运行了包2次,每个包在ORDERS_ARCHIVE表中共4行。 3行9813,1每行9817。

我在那里获得正确的行数,所以我相信触发器正在正确触发。相反,正在发生的是逻辑不正确。由于OrderID在ORDERS表中不是唯一的,因此数据库引擎将选择恰好满足搜索条件的第一行。只是碰巧它每次都选择相同的行(ItemNo = 1),但由于没有ORDER BY子句就没有保证顺序,这只是随机的或者引擎选择但没有行为的工件我将继续保持一致。

你如何解决这个问题?

修复触发器。仅在OrderID上连接到插入的虚拟表会导致多行满足条件。

create trigger 
    trUpdate
ON
    dbo.ORDERS
    AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;
    -- This trigger will add all the rows from the ORDERS table
    -- that match what was just inserted based on OrderID and ItemNo
    INSERT INTO dbo.ORDERS_ARCHIVE 
    SELECT O.* 
    FROM dbo.ORDERS O
    INNER JOIN INSERTED I
         ON O.OrderID = I.OrderID
         AND O.ItemNo = I.ItemNo;
END

现在,当我运行ETL时,我在ORDERS_ARCHIVE中看到4行,其中包含正确的ItemNo值。