2015-01-03 36 views
0

/其他解决方案,我有两个相关的表:光标复杂INSERT触发器

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 [email protected]; 

    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 [email protected][email protected][email protected][email protected] where [email protected] 
GO 

这只是一个计算这个领域^^

只有当我跑了,我才意识到触发器不是发生在每一行,而是发生在每一条语句上,所以例如TotalReads字段是beig只更新一行。 所以我开始阅读关于游标,但不能写一个来处理我的需求。

我会appriciate任何帮助。如果没有光标的话可以更有效地做到这一点,我很想知道。

谢谢!

编辑

这是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)[email protected]) 
END 

INSERT INTO @returnList 
SELECT @stringToSplit 

RETURN 
END 
+1

可怜的模式:1)在列dp4中只存储一个值,而不是存储逗号分隔列表。 2)而不是'calculateData'表创建一个calculateData'View'或'Table-Valued-Function',它不存储任何数据,而是在运行中计算数据。 –

+0

当你说*复杂的插入触发器*并且你在同一个句子中提到*光标*时,它会让我发抖。一个触发器应该尽可能小和精益** - 它不应该做任何广泛的处理!触发器在触发它的语句的上下文中执行 - 如果它耗尽了大量时间,则您的应用程序变得缓慢且缓慢。 **不要这样做!**相反:请在单独的表格中注明需要更新ID 4,7,23,37(或任何他们将会更新)的行,这就是全部。让一个单独的计划过程然后做计算+更新 –

+0

感谢您的意见。此插入仅在插入时发生。所以也许它不会是一个坏主意。@marc_s,你的意思是创建一个包含所有dp4值的表格?接着?你能详细说明一下吗? – Dvirski

回答

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 

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

+0

谢谢你,但它告诉我,我不能在更新语句中使用SUM。所以我试图得到一些作为表变量,它设置为整列以错误的总和。此过程仅在插入时发生。所以它很少使用..你能帮我声明一个游标吗?我也编辑和复制了该功能。也许这会有所帮助。谢谢! :] – Dvirski