【问题标题】:How to check and update table in trigger in sql server如何在sql server的触发器中检查和更新表
【发布时间】:2018-12-05 08:14:28
【问题描述】:

您好,我有一张这样的数据表...

A     B    C     D    E 
100  A1  Hard  Dece  100
100  A1  Hard  Jan   200
100  A1  SOFT  Jan   200
200  A2  Hard  Dec   250
200  A2  SOFT  Jan   300
----------------------------

然后,当在此表上执行插入或更新时,我需要执行触发器,数据应如下所示

A    B   C     F
100  A1 Hard   Dece:100;Jan:200
100  A1 SOFT   Jan:200
200  A2 Hard   Dec:250
------------------------

我已经创建了一个类似下面的触发器

ALTER TRIGGER [dbo].[trgInsert9] ON [roll].[dbo].[testing]
after INSERT,Update
AS
Declare @Counter int=0
Declare @max int
Declare @re int
select *  into  #t13  from (select A,B,C,[D] + ':' + cast([E] as varchar) as Common  from [roll].[dbo].[testing]) as X
select * into #t24 from (
SELECT t2.A,t2.B,t2.C,  
STUFF((SELECT ';' + CAST(Common AS varchar) 
FROM #t13 t1  where t1.A =t2.A and t1.B=t2.B and t1.C=t2.C
FOR XML PATH('')), 1 ,1, '') AS List
FROM #t13 t2
GROUP BY t2.A,t2.B,t2.C) as XT
SET @max=(select count(A) from #t24)
while(@Counter<@max)
BEGIN
if exits(select count(t11.A) from Test123 t11 left join #t24 f on t11.A=f.A 
 where t11.A=f.A and t11.B=f.B and t11.C=f.C
and t11.ValueList=f.ValueList)
  Begin
update Test123 set Test123.ValueList=t4.ValueList from #t24 t4
where
 Test123.A=t4.A and Test123.B=t4.B and Test123.C=t4.C
END
ELSE
BEGIN
insert into Test123
select * from #24 t8
END
SET @Counter=@Counter+1
END
drop table #t13
drop table #t24

但是我没有得到正确的结果,比如第一个被插入然后它没有更新意味着它正在将它添加到下一个,如下所示:-

A   B  C  F
100 A1 Hard Dece:100
100 A1  Hard Dece:100;jan:200
------------------------------

但是在临时表中我得到了正确的结果,当我尝试插入或更新时,问题正在发生,请帮助我。

【问题讨论】:

  • 你能解释一下你想在这里实现什么吗?
  • SQL 甚至无效...(它有IF EXITS,而不是IF EXISTS)。此外,触发器从不引用inserteddeleted,被称为trgInsert9 但发生在INSERT UPDATE。别名也没有任何帮助,Bad habits to kick : using table aliases like (a, b, c) or (t1, t2, t3),并且没有格式/空格甚至开始提高可读性。 @MitchWheat 是对的,这是一个真正可怕的触发器。我建议我们在这里找出你的真正目标,然后重新开始。
  • 为什么你只有一行200 A2 Hard Dec:250?您如何按这些行分组?
  • 不要这样做。在一列中存储多个值只是为以后存储问题。每行每列一个值。这是一条非常简单的规则。

标签: sql sql-server sql-server-2008


【解决方案1】:

您的触发器完全乱码。首先,您应该学习如何格式化您的 sql 脚本。我在 SO 中找到了这个 SQL Formatting standards 标题。请阅读。没有关于格式的特定规则,但主要规则是您的查询应该是可读的!

另外,您不应该对触发器进行大量计算。会影响sql性能。

以我的拙见; DELETE 然后 INSERT 你的相关行(到第二个表)比 IF EXISTS() --> UPDATEELSE --> INSERT 过程更好。

我已经为您创建了示例,您可以查看:

--DROP TABLE Testing;

CREATE TABLE Testing
(
     A  INT
    ,B  VARCHAR(100)
    ,C  VARCHAR(100)
    ,D  VARCHAR(100)
    ,E  INT
);

--DROP TABLE Test123;

CREATE TABLE Test123
(
     A  INT
    ,B  VARCHAR(100)
    ,C  VARCHAR(100)
    ,F  VARCHAR(MAX)
);


--DROP TRIGGER [dbo].[trgInsert9] ;

CREATE TRIGGER [dbo].[trgInsert9] 
    ON /*[roll].*/[dbo].[Testing]
AFTER INSERT,UPDATE,DELETE
AS

DELETE FROM [dbo].Test123
WHERE EXISTS (
                SELECT 1
                FROM INSERTED I
                WHERE Test123.A = I.A
                AND Test123.B = I.B
                AND Test123.C = I.C
                )

DELETE FROM [dbo].Test123
WHERE EXISTS (
                SELECT 1
                FROM DELETED I
                WHERE Test123.A = I.A
                AND Test123.B = I.B
                AND Test123.C = I.C
                )

SELECT DISTINCT A,B,C 
INTO #List 
FROM INSERTED

INSERT INTO [dbo].Test123(A,B,C,F)
SELECT A,B,C,STUFF((SELECT ';' + CAST(D AS varchar) +':'+ CAST(E AS varchar) 
                    FROM Testing T  
                    WHERE T.A =L.A 
                    AND T.B=L.B
                    AND T.C=L.C
                    FOR XML PATH('')), 1 ,1, '') 
FROM #List L
GO

DELETE FROM Testing;
INSERT INTO Testing
VALUES
 (100,'A1','Hard','Dece',100)
,(100,'A1','Hard','Jan ',200)
,(100,'A1','SOFT','Jan ',200)
,(200,'A2','Hard','Dec ',250)
,(200,'A2','SOFT','Jan ',300);

SELECT * FROM Testing
SELECT * FROM Test123

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-13
    • 2016-11-03
    • 2011-06-03
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多