SQL-Server Trigger on Insert into a table,1列到6在同一个表中

时间:2017-04-10 11:46:14

标签: sql-server

我花了很多时间调查这是否可以在数据库之外完成,但老实说我不这么认为,也不是很容易。我们使用VBA通过Access 2010访问表中的数据,所以我想我可以做到 通过前端软件中的操作。容易完成但是我无法控制两种排列。

我有一个包含多列的表[TableData]。我们有一些外部提供的软件,一次填充表约20-30行。其中一个字段[波动]目前允许我们传输最多60个字符的数据,我们的目的是以1.1,1.2,1.3,1.4,1.5,1.6格式发送数据,其中我们有六个数字,最多两个小数以逗号分隔的地方,没有空格。列名称Fluc1,Fluc2,Flu3等。

我想要做的是在SQL数据库中创建一个触发器,该数据库在插入行后操作,只有当存在由五个逗号分隔的6个值时才将上面的内容拆分为六个新列。

然后我需要完成6个值的数学运算,但至少我会让它们完成数字以完成数学运算。

我对触发器一无所知,因此非常感谢任何帮助。

示例数据示例如下: 101.23,100.45,101.56,102.89,101,74,100.25 1.05,1.09,1.05,0.99,0.99,0.98 等

我有VBA代码来分割数据,并且事后会通过SELECT查询执行此操作,但由于我无法控制从外部软件输入的数据,因此认为触发器会更有用。

VBA代码。

'This function returns the string data sperated by commas

Public Function FluctuationSeperation(strFluctuationData As String) As Variant

   Dim strTest As String
   Dim strArray() As String
   Dim intCount As Integer

   strArray = Split(strFluctuationData, ",")
   Dim arr(5) As Variant

   For intCount = LBound(strArray) To UBound(strArray)
      arr(intCount) = Trim(strArray(intCount))
   Next
   FluctuationSeperation = arr
End Function

1 个答案:

答案 0 :(得分:1)

编写触发器时,需要注意它可以为多个插入的行启动。有inserted内置表别名可用于此目的。您需要遍历所有插入的记录并单独更新它们。您需要使用主键(我已假设列id)来匹配插入的记录和要更新的记录。

  CREATE TRIGGER TableData_ForInsert 
    ON [TableData] 
    AFTER INSERT
    AS
    BEGIN
        DECLARE @id int
        DECLARE @Fluctuation varchar(max)
        DECLARE i CURSOR FOR
            SELECT id, Fluctuation FROM inserted        

        FETCH NEXT FROM i INTO @id, @Fluctuation
        WHILE @@FETCH_STATUS = 0
        BEGIN
              DECLARE @pos1 int =  charindex(',',@Fluctuation)
              DECLARE @pos2 int =  charindex(',',@Fluctuation, @pos1+1)
              DECLARE @pos3 int =  charindex(',',@Fluctuation, @pos2+1)
              DECLARE @pos4 int =  charindex(',',@Fluctuation, @pos3+1)

              UPDATE [TableData]
              SET fluc1 = ltrim(substring(@Fluctuation,1,@pos1-1)),
                  fluc2 = ltrim(substring(@Fluctuation,@pos1+1,@pos2-@pos1-1)),
                  fluc3 = ltrim(substring(@Fluctuation,@pos2+1,@pos3-@pos2-1)),
                  fluc4 = ltrim(substring(@Fluctuation,@pos3+1,@pos4-@pos3-1)),
                  fluc5 = ltrim(substring(@Fluctuation,@pos4+1,999))
              WHERE id = @id  -- need to find TableData record to update by inserted id

            FETCH NEXT FROM i INTO @id, @Fluctuation
        END            
    END

但是因为游标在many cases considered as a bad practice中,所以最好将其写为基于集合的命令。它可以通过APPLY子句实现,如下所示:

CREATE TRIGGER TableData_ForInsert 
ON [TableData] 
AFTER INSERT
AS
BEGIN
    UPDATE t SET 
        fluc1 = SUBSTRING(t.fluctuation, 0, i1.i),
        fluc2 = SUBSTRING(t.fluctuation, i1.i+1, i2.i - i1.i -1),    
        fluc3 = SUBSTRING(t.fluctuation, i2.i+1, i3.i - i2.i -1),    
        fluc4 = SUBSTRING(t.fluctuation, i3.i+1, i4.i - i3.i -1),    
        fluc5 = SUBSTRING(t.fluctuation, i4.i+1, 999)
    FROM [TableData] t
        OUTER APPLY (select charindex(',', t.fluctuation) as i)  i1
        OUTER APPLY (select charindex(',', t.fluctuation, i1.i+1) as i)  i2
        OUTER APPLY (select charindex(',', t.fluctuation, i2.i+1) as i)  i3
        OUTER APPLY (select charindex(',', t.fluctuation, i3.i+1) as i)  i4
    JOIN INSERTED new ON new.ID = t.ID -- need to find TableData record to update by inserted id
END

这个代码示例缺少处理格式错误的字符串,它总是期望5个数字由4个逗号分隔。

有关如何在SQL Server中拆分字符串的更多提示,请选中this link

测试用例:

DECLARE @test TABLE
(
id int,
Fluctuation varchar(max), 
fluc1 numeric(9,3) NULL,  
fluc2 numeric(9,3) NULL,
fluc3 numeric(9,3) NULL,
fluc4 numeric(9,3) NULL,
fluc5 numeric(9,3) NULL
)

INSERT INTO @test (id, Fluctuation) VALUES(1, '1.2,5,8.52,6,7.521')
INSERT INTO @test (id, Fluctuation) VALUES(2, '2.2,6,9.52,7,8.521')
INSERT INTO @test (id, Fluctuation) VALUES(3, '2.5,3,4.52,9,7.522')
INSERT INTO @test (id, Fluctuation) VALUES(4, '2.53,4.52,97.522') -- this fails

UPDATE t SET 
    fluc1 = CASE WHEN i1.i<0 THEN NULL ELSE SUBSTRING(t.fluctuation, 0, i1.i) END,
    fluc2 = CASE WHEN i2.i<0 THEN NULL ELSE SUBSTRING(t.fluctuation, i1.i+1, i2.i - i1.i -1) END,    
    fluc3 = CASE WHEN i3.i<0 THEN NULL ELSE SUBSTRING(t.fluctuation, i2.i+1, i3.i - i2.i -1) END,    
    fluc4 = CASE WHEN i4.i<0 THEN NULL ELSE SUBSTRING(t.fluctuation, i3.i+1, i4.i - i3.i -1) END,    
    fluc5 = CASE WHEN i4.i<0 THEN NULL ELSE SUBSTRING(t.fluctuation, i4.i+1, 999) END
FROM @test t
    OUTER APPLY (select charindex(',', t.fluctuation) as i)  i1
    OUTER APPLY (select charindex(',', t.fluctuation, i1.i+1) as i)  i2
    OUTER APPLY (select charindex(',', t.fluctuation, i2.i+1) as i)  i3
    OUTER APPLY (select charindex(',', t.fluctuation, i3.i+1) as i)  i4

SELECT * FROM @test