复杂插入触发器的游标/其他解决方案

时间:2015-01-03 22:33:43

标签: sql-server sql-server-2008 triggers cursor

我有两个相关的表格:

create table readData
(
    readDataId int identity primary key,    
    dp4 varchar(300),
    fields....

);
create table calculatedData
(
    calculatedDataId int identity primary key,
    readDataId int foreign key references readData (readDataId),
    fields...
    calculated field 1,
    calculated field 2,
    calculated field 3,
    etc..
);

表中的dp4字段如下所示:'138,73,117,112'。

我有一个处理它的存储过程。数据被插入到calculateData表的某些字段中,插入到select中,然后我需要将dp4字段分解为四个变量,进行一些计算并更新calculatedData中的计算字段。 必须为每一行完成此操作。

我写了一个函数来分解dp4字段然后我在触发器中使用它:

CREATE TRIGGER trgAfterInsert ON calculatedData
FOR INSERT
AS
    declare @readDataId int;
    declare @dp4 varchar(300);
    declare @dp0 varchar(300);
    declare @dp1 varchar(300);
    declare @dp2 varchar(300);
    declare @dp3 varchar(300);
    declare @dp0Int int;
    declare @dp1Int int;
    declare @dp2Int int;
    declare @dp3Int int;

    select @readDataId=i.readDataId from inserted i;
    select @dp4=dp4 from readData where readDataId=@readDataId;

    select @dp0=dp from dbo.splitstring(@dp4) where id=1;
    select @dp1=dp from dbo.splitstring(@dp4) where id=2;
    select @dp2=dp from dbo.splitstring(@dp4) where id=3;
    select @dp3=dp from dbo.splitstring(@dp4) where id=4;

    select @dp0Int=cast(@dp0 as int);
    select @dp1Int=cast(@dp1 as int);
    select @dp2Int=cast(@dp2 as int);
    select @dp3Int=cast(@dp3 as int);

    update calculatedData set TotalReads=@dp0Int+@dp1Int+@dp2Int+@dp3Int where readDataId=@readDataId
GO

这只是一个用这个字段计算^^

只有当我运行它时,才意识到触发器不是每一行都发生,而是每个语句。例如,TotalReads字段仅针对一行进行更新。 所以我开始阅读游标但不能写一个来处理我的需求。

我会赞美任何帮助。如果有一种更有效的方法,没有光标,我很想知道。

谢谢!

修改

这是splitString函数:

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([id] [int] identity,[dp] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END

1 个答案:

答案 0 :(得分:0)

你的问题从这里开始:

select @readDataId=i.readDataId from inserted i;

为了提高效率,SQL Server不会在每次插入行时触发触发器。它将为多行触发一次触发器。我从来没有挖得足够深,无法找出阈值是什么,所以我只是假设inserted表中会有多行。

光标在关系世界中是个坏词。几乎每次你想到使用它,你都做错了。这是基于您的代码的即兴版本:

CREATE TRIGGER trgAfterInsert ON calculatedData
FOR INSERT
AS
    DECLARE @tmp TABLE (
        readDataID int,
        dp int
    )

    INSERT INTO @tmp (readDataID, dp)
        SELECT      i.readDataID,
                    CAST(s.dp AS INT)
        FROM        inserted i
        CROSS APPLY dbo.SplitString(i.dp4) s

    UPDATE c
        SET c.TotalReads = SUM(tmp.dp)
        FROM @tmp tmp
        INNER JOIN calculatedData c ON tmp.readDataId = c.readDataID
GO

由于缺乏数据,我还没有测试过这段代码。它应该给你一个指针。如果您需要帮助,请发布一些数据。