Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何优化触发器? 创建触发器T 关于表2 插入后 作为 声明@bunded\u t int, @name_t varchar(20) 选择@name\u t=name\u t 从插入 选择@bunded\u t=bunded\u t 来自表1 其中name\u t=@name\u t 如果@bunded\u t=100时,为什么会回滚他们的更改?而且,如果没有更多的信息,很难说它是否得到了优化。对于初学者,只需从SSMS中的触发器运行update语句并捕获查询计划。这应该告诉你很多。@marc_的确如此。我刚刚尝试了这个(随机值)INSERT-INTO-TABLE_2 values('A','B'),('B','Z'),('S','A'),('A','S'),('D','G'),我只运行了一次update函数。@JamesL:在触发器中,您总是在一个事务中-或者在您明确定义的事务中,或者如果不是这样,然后您就在语句的隐式事务中。@user3832856:这就是我的解决方案所做的-如果值小于100,则更新-如果值大于等于100,则忽略它。这里不需要回滚!JamesL.:是-当然-复制粘贴错误-修复,谢谢!这仍然会导致只更新一次。如果我插入上面注释中给出的值,我会得到:(1行受影响)(5行受影响),因此触发器只更新一次,而不是5@user3832856:受影响的1行用于将语句插入表2,第二条消息5行受影响是触发器更新5行(因此它更新了所有插入行的TABLE_1)@user3832856:是的,绝对正确 -- create the two tables CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50)) CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT) GO -- create trigger on "TABLE_2" to update "TABLE_1" CREATE TRIGGER T2Insert ON TABLE_2 AFTER INSERT AS UPDATE T1 SET Bought = Bought + 1 FROM TABLE_1 T1 INNER JOIN Inserted i ON T1.ProdName = i.ProdName WHERE T1.Bought < 100 GO -- initialize TABLE_1 with some seed data INSERT INTO dbo.TABLE_1 (ProdName, Bought) VALUES ( 'Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100) -- insert new values into TABLE_2 INSERT INTO dbo.TABLE_2 (ProdName) VALUES ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4') -- get data to check SELECT * FROM dbo.TABLE_1 CREATE TRIGGER T2Insert ON TABLE_2 AFTER INSERT AS -- declare table variable to hold names and update counts DECLARE @UpdateCount TABLE (Name VARCHAR(50), UpdCount INT) -- from the "Inserted" table, determine which names are being -- inserted how many times using GROUP BY INSERT INTO @UpdateCount (Name, UpdCount) SELECT ProdName, COUNT(*) FROM Inserted GROUP BY ProdName -- now join to this temporary table, and update as many times -- as needed (instead of +1 for all cases) UPDATE T1 SET Bought = Bought + uc.UpdCount FROM TABLE_1 T1 INNER JOIN @UpdateCount uc ON uc.Name = T1.ProdName WHERE T1.Bought < 100 GO_Sql_Sql Server_Tsql - Fatal编程技术网

Sql 如何优化触发器? 创建触发器T 关于表2 插入后 作为 声明@bunded\u t int, @name_t varchar(20) 选择@name\u t=name\u t 从插入 选择@bunded\u t=bunded\u t 来自表1 其中name\u t=@name\u t 如果@bunded\u t=100时,为什么会回滚他们的更改?而且,如果没有更多的信息,很难说它是否得到了优化。对于初学者,只需从SSMS中的触发器运行update语句并捕获查询计划。这应该告诉你很多。@marc_的确如此。我刚刚尝试了这个(随机值)INSERT-INTO-TABLE_2 values('A','B'),('B','Z'),('S','A'),('A','S'),('D','G'),我只运行了一次update函数。@JamesL:在触发器中,您总是在一个事务中-或者在您明确定义的事务中,或者如果不是这样,然后您就在语句的隐式事务中。@user3832856:这就是我的解决方案所做的-如果值小于100,则更新-如果值大于等于100,则忽略它。这里不需要回滚!JamesL.:是-当然-复制粘贴错误-修复,谢谢!这仍然会导致只更新一次。如果我插入上面注释中给出的值,我会得到:(1行受影响)(5行受影响),因此触发器只更新一次,而不是5@user3832856:受影响的1行用于将语句插入表2,第二条消息5行受影响是触发器更新5行(因此它更新了所有插入行的TABLE_1)@user3832856:是的,绝对正确 -- create the two tables CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50)) CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT) GO -- create trigger on "TABLE_2" to update "TABLE_1" CREATE TRIGGER T2Insert ON TABLE_2 AFTER INSERT AS UPDATE T1 SET Bought = Bought + 1 FROM TABLE_1 T1 INNER JOIN Inserted i ON T1.ProdName = i.ProdName WHERE T1.Bought < 100 GO -- initialize TABLE_1 with some seed data INSERT INTO dbo.TABLE_1 (ProdName, Bought) VALUES ( 'Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100) -- insert new values into TABLE_2 INSERT INTO dbo.TABLE_2 (ProdName) VALUES ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4') -- get data to check SELECT * FROM dbo.TABLE_1 CREATE TRIGGER T2Insert ON TABLE_2 AFTER INSERT AS -- declare table variable to hold names and update counts DECLARE @UpdateCount TABLE (Name VARCHAR(50), UpdCount INT) -- from the "Inserted" table, determine which names are being -- inserted how many times using GROUP BY INSERT INTO @UpdateCount (Name, UpdCount) SELECT ProdName, COUNT(*) FROM Inserted GROUP BY ProdName -- now join to this temporary table, and update as many times -- as needed (instead of +1 for all cases) UPDATE T1 SET Bought = Bought + uc.UpdCount FROM TABLE_1 T1 INNER JOIN @UpdateCount uc ON uc.Name = T1.ProdName WHERE T1.Bought < 100 GO

Sql 如何优化触发器? 创建触发器T 关于表2 插入后 作为 声明@bunded\u t int, @name_t varchar(20) 选择@name\u t=name\u t 从插入 选择@bunded\u t=bunded\u t 来自表1 其中name\u t=@name\u t 如果@bunded\u t=100时,为什么会回滚他们的更改?而且,如果没有更多的信息,很难说它是否得到了优化。对于初学者,只需从SSMS中的触发器运行update语句并捕获查询计划。这应该告诉你很多。@marc_的确如此。我刚刚尝试了这个(随机值)INSERT-INTO-TABLE_2 values('A','B'),('B','Z'),('S','A'),('A','S'),('D','G'),我只运行了一次update函数。@JamesL:在触发器中,您总是在一个事务中-或者在您明确定义的事务中,或者如果不是这样,然后您就在语句的隐式事务中。@user3832856:这就是我的解决方案所做的-如果值小于100,则更新-如果值大于等于100,则忽略它。这里不需要回滚!JamesL.:是-当然-复制粘贴错误-修复,谢谢!这仍然会导致只更新一次。如果我插入上面注释中给出的值,我会得到:(1行受影响)(5行受影响),因此触发器只更新一次,而不是5@user3832856:受影响的1行用于将语句插入表2,第二条消息5行受影响是触发器更新5行(因此它更新了所有插入行的TABLE_1)@user3832856:是的,绝对正确 -- create the two tables CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50)) CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT) GO -- create trigger on "TABLE_2" to update "TABLE_1" CREATE TRIGGER T2Insert ON TABLE_2 AFTER INSERT AS UPDATE T1 SET Bought = Bought + 1 FROM TABLE_1 T1 INNER JOIN Inserted i ON T1.ProdName = i.ProdName WHERE T1.Bought < 100 GO -- initialize TABLE_1 with some seed data INSERT INTO dbo.TABLE_1 (ProdName, Bought) VALUES ( 'Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100) -- insert new values into TABLE_2 INSERT INTO dbo.TABLE_2 (ProdName) VALUES ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4') -- get data to check SELECT * FROM dbo.TABLE_1 CREATE TRIGGER T2Insert ON TABLE_2 AFTER INSERT AS -- declare table variable to hold names and update counts DECLARE @UpdateCount TABLE (Name VARCHAR(50), UpdCount INT) -- from the "Inserted" table, determine which names are being -- inserted how many times using GROUP BY INSERT INTO @UpdateCount (Name, UpdCount) SELECT ProdName, COUNT(*) FROM Inserted GROUP BY ProdName -- now join to this temporary table, and update as many times -- as needed (instead of +1 for all cases) UPDATE T1 SET Bought = Bought + uc.UpdCount FROM TABLE_1 T1 INNER JOIN @UpdateCount uc ON uc.Name = T1.ProdName WHERE T1.Bought < 100 GO,sql,sql-server,tsql,Sql,Sql Server,Tsql,在“TABLE_2”中插入之后,我要更新的列(TABLE_1)应该包含50到100之间的值。所以我问这个触发器是否尽可能的专业和优化?或者我有一些可能导致错误/安全问题的缺陷。基本上,您需要完全重写触发器,使其基于集,并且能够处理插入的伪表中的多行 幸运的是,在我看来,这也让它变得更容易尝试以下方式: CREATE TRIGGER T ON TABLE_2 AFTER INSERT AS DECLARE @bought_t int, @name_t va

在“TABLE_2”中插入之后,我要更新的列(
TABLE_1
)应该包含50到100之间的值。所以我问这个触发器是否尽可能的专业和优化?或者我有一些可能导致错误/安全问题的缺陷。

基本上,您需要完全重写触发器,使其基于集,并且能够处理
插入的
伪表中的多行

幸运的是,在我看来,这也让它变得更容易尝试以下方式:

CREATE TRIGGER T 
ON TABLE_2 
AFTER INSERT 
AS
     DECLARE @bought_t int,
             @name_t varchar(20)

     SELECT @name_t = name_t 
     FROM inserted

     SELECT @bought_t = bought_t 
     FROM TABLE_1 
     WHERE name_t = @name_t

     IF @bought_t < 100 
     BEGIN
         UPDATE TABLE_1
         SET bought_t = @bought_t + 1
         WHERE TABLE_1.name_t = @name_t
     END
     ELSE 
        ROLLBACK TRANSACTION
-- create the two tables
CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50))
CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT)
GO

-- create trigger on "TABLE_2" to update "TABLE_1"    
CREATE TRIGGER T2Insert
ON TABLE_2
AFTER INSERT
AS
    UPDATE T1
    SET Bought = Bought + 1
    FROM TABLE_1 T1
    INNER JOIN Inserted i ON T1.ProdName = i.ProdName
    WHERE T1.Bought < 100
GO

-- initialize TABLE_1 with some seed data
INSERT INTO dbo.TABLE_1 (ProdName, Bought)
VALUES ( 'Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100)

-- insert new values into TABLE_2
INSERT INTO dbo.TABLE_2 (ProdName)
VALUES  ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4')

-- get data to check
SELECT * FROM dbo.TABLE_1

您的触发器有一个主要缺陷,您似乎认为它每行调用一次,但事实并非如此。触发器将对每条语句触发一次,因此,如果导致此触发器触发的
INSERT
语句插入了25行,则触发器将触发一次,但是
Inserted
伪表将包含25行。您的代码将在此处选择这25行中的哪一行<代码>选择@name\u t=name\u t FROM inserted
-这是不确定的,您将得到任意一行,并将忽略所有其他行。你需要重写你的触发器来考虑这一点!您如何知道它在交易中?如果
插入到
表2中的
没有以事务开始,则如果触发器曾经运行
回滚
代码,则使用
否则回滚
将抛出错误。另外,您如何知道还将回滚哪些内容。如果其他人编写过代码,他们是否会意识到当
购买的值>=100时,为什么会回滚他们的更改?而且,如果没有更多的信息,很难说它是否得到了优化。对于初学者,只需从SSMS中的触发器运行
update
语句并捕获查询计划。这应该告诉你很多。@marc_的确如此。我刚刚尝试了这个(随机值)
INSERT-INTO-TABLE_2 values('A','B'),('B','Z'),('S','A'),('A','S'),('D','G')
,我只运行了一次update函数。@JamesL:在触发器中,您总是在一个事务中-或者在您明确定义的事务中,或者如果不是这样,然后您就在语句的隐式事务中。@user3832856:这就是我的解决方案所做的-如果值小于100,则更新-如果值大于等于100,则忽略它。这里不需要
回滚
!JamesL.:是-当然-复制粘贴错误-修复,谢谢!这仍然会导致只更新一次。如果我插入上面注释中给出的值,我会得到:
(1行受影响)(5行受影响)
,因此触发器只更新一次,而不是5@user3832856:受影响的
1行
用于
语句插入
表2
,第二条消息
5行受影响
是触发器更新5行(因此它更新了所有插入行的
TABLE_1
)@user3832856:是的,绝对正确
-- create the two tables
CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50))
CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT)
GO

-- create trigger on "TABLE_2" to update "TABLE_1"    
CREATE TRIGGER T2Insert
ON TABLE_2
AFTER INSERT
AS
    UPDATE T1
    SET Bought = Bought + 1
    FROM TABLE_1 T1
    INNER JOIN Inserted i ON T1.ProdName = i.ProdName
    WHERE T1.Bought < 100
GO

-- initialize TABLE_1 with some seed data
INSERT INTO dbo.TABLE_1 (ProdName, Bought)
VALUES ( 'Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100)

-- insert new values into TABLE_2
INSERT INTO dbo.TABLE_2 (ProdName)
VALUES  ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4')

-- get data to check
SELECT * FROM dbo.TABLE_1
CREATE TRIGGER T2Insert
ON TABLE_2
AFTER INSERT
AS
    -- declare table variable to hold names and update counts 
    DECLARE @UpdateCount TABLE (Name VARCHAR(50), UpdCount INT)

    -- from the "Inserted" table, determine which names are being
    -- inserted how many times using GROUP BY    
    INSERT INTO @UpdateCount (Name, UpdCount)
        SELECT ProdName, COUNT(*)
        FROM Inserted
        GROUP BY ProdName

    -- now join to this temporary table, and update as many times
    -- as needed (instead of +1 for all cases)
    UPDATE T1
    SET Bought = Bought + uc.UpdCount
    FROM TABLE_1 T1
    INNER JOIN @UpdateCount uc ON uc.Name = T1.ProdName
    WHERE T1.Bought < 100
GO