回滚 SQL 事务而不返回错误
Rollback SQL transaction without returning an error
考虑下面的触发器
ALTER TRIGGER [dbo].[trgUpdateTasks]
ON [dbo].[Tasks]
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Check if job has quotation --
DECLARE @JobID NUMERIC(18,0)
DECLARE @QuotationID UNIQUEIDENTIFIER
SELECT @JobID = INSERTED.JobID FROM INSERTED
SET @QuotationID = (SELECT TOP 1 QuotationID FROM Jobs WHERE (JobID=@JobID))
--------------------------------
IF( NOT (@QuotationID IS NULL) )
BEGIN
ROLLBACK TRANSACTION;
END;
END
这个想法是阻止对 Tasks 记录进行任何更改,如果它绑定到具有QuotationID 字段中的值。
之所以有效,是因为当满足这些条件时,不会保存更改。然而,尽管如此,一个错误被 returned 到导致它崩溃的应用程序。不幸的是,无法更新应用程序以忽略此类错误,因为它 运行 在一台不允许安装更新的 exe 的非常旧的 Windows 机器上。
有没有办法设置触发器为NOT return回滚时报错,这样对于应用来说,改变已经正常保存了吗?
如果您使用代替触发器,则只需在 quotation_id 为空时更新。
此外,触发器中不应该有变量,因为它应该允许一次更新多行。
/* *** DDL and Test Data *** */
USE tempdb;
GO
SET ANSI_NULLS, QUOTED_IDENTIFIER, ANSI_PADDING ON;
GO
CREATE TABLE dbo.Tasks
(
TaskID int NOT NULL PRIMARY KEY
,JobID int NOT NULL
,Task varchar(50) NOT NULL
,TaskStart date NOT NULL
,TaskEnd date NULL
);
GO
INSERT INTO dbo.Tasks
VALUES (1, 1, 'Task1 Job1', '20210901', '20210902')
,(2, 1, 'Task2 Job1', '20210902', NULL)
,(3, 2, 'Task1 Job2', '20210903', '20210904')
,(4, 2, 'Task2 Job2', '20210905', '20210906')
,(5, 3, 'Task1 Job3', '20210910', '20210911')
,(6, 3, 'Task2 Job3', '20210915', NULL)
,(7, 4, 'Task1 Job4', '20210903', '20210904')
,(8, 4, 'Task2 Job4', '20210905', '20210906');
GO
CREATE TABLE dbo.Jobs
(
JobID int NOT NULL PRIMARY KEY
,QuotationID uniqueidentifier NULL
,Job varchar(50) NOT NULL
);
GO
INSERT INTO dbo.Jobs
VALUES (1, 'F15EAF03-4F45-40E8-85D6-D89B20E00F38', 'Job1')
,(2, NULL, 'Job2')
,(3, 'F15EAF03-4F45-40E8-85D6-D89B20E00F38', 'Job3')
,(4, '3D74F043-2FAC-4C91-8288-13D71C6558C8', 'Job4');
GO
/* *** End DDL and Test Data *** */
/* *** Create Trigger *** */
SET ANSI_NULLS, QUOTED_IDENTIFIER ON;
GO
CREATE TRIGGER dbo.Tasks_TR_U
ON dbo.Tasks
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT, XACT_ABORT ON;
UPDATE T
SET Task = I.Task
,TaskStart = I.TaskStart
,TaskEnd = I.TaskEnd
FROM dbo.Tasks T
JOIN inserted I
ON T.TaskID = I.TaskID
WHERE EXISTS
-- Only QuotationID of NULL allowed
(
SELECT 1
FROM dbo.Jobs J
WHERE J.JobID = T.JobID
AND J.QuotationID IS NULL
)
-- Only update if any changes
AND NOT
(
T.Task = I.Task
AND T.TaskStart = I.TaskStart
AND ISNULL(T.TaskEnd, '1900') = ISNULL(I.TaskEnd, '1900')
);
END
GO
/* *** End Create Trigger *** */
/* Check data in tables. */
select * from dbo.Tasks;
select * from dbo.Jobs;
/* Run test */
UPDATE dbo.Tasks
SET Task = Task + ' Updated'
/* Only JobId = 2 should be updated. */
select * from dbo.Tasks;
/* Drop Test Tables
DROP TABLE dbo.Tasks;
DROP TABLE dbo.Jobs;
*/
考虑下面的触发器
ALTER TRIGGER [dbo].[trgUpdateTasks]
ON [dbo].[Tasks]
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Check if job has quotation --
DECLARE @JobID NUMERIC(18,0)
DECLARE @QuotationID UNIQUEIDENTIFIER
SELECT @JobID = INSERTED.JobID FROM INSERTED
SET @QuotationID = (SELECT TOP 1 QuotationID FROM Jobs WHERE (JobID=@JobID))
--------------------------------
IF( NOT (@QuotationID IS NULL) )
BEGIN
ROLLBACK TRANSACTION;
END;
END
这个想法是阻止对 Tasks 记录进行任何更改,如果它绑定到具有QuotationID 字段中的值。
之所以有效,是因为当满足这些条件时,不会保存更改。然而,尽管如此,一个错误被 returned 到导致它崩溃的应用程序。不幸的是,无法更新应用程序以忽略此类错误,因为它 运行 在一台不允许安装更新的 exe 的非常旧的 Windows 机器上。
有没有办法设置触发器为NOT return回滚时报错,这样对于应用来说,改变已经正常保存了吗?
如果您使用代替触发器,则只需在 quotation_id 为空时更新。 此外,触发器中不应该有变量,因为它应该允许一次更新多行。
/* *** DDL and Test Data *** */
USE tempdb;
GO
SET ANSI_NULLS, QUOTED_IDENTIFIER, ANSI_PADDING ON;
GO
CREATE TABLE dbo.Tasks
(
TaskID int NOT NULL PRIMARY KEY
,JobID int NOT NULL
,Task varchar(50) NOT NULL
,TaskStart date NOT NULL
,TaskEnd date NULL
);
GO
INSERT INTO dbo.Tasks
VALUES (1, 1, 'Task1 Job1', '20210901', '20210902')
,(2, 1, 'Task2 Job1', '20210902', NULL)
,(3, 2, 'Task1 Job2', '20210903', '20210904')
,(4, 2, 'Task2 Job2', '20210905', '20210906')
,(5, 3, 'Task1 Job3', '20210910', '20210911')
,(6, 3, 'Task2 Job3', '20210915', NULL)
,(7, 4, 'Task1 Job4', '20210903', '20210904')
,(8, 4, 'Task2 Job4', '20210905', '20210906');
GO
CREATE TABLE dbo.Jobs
(
JobID int NOT NULL PRIMARY KEY
,QuotationID uniqueidentifier NULL
,Job varchar(50) NOT NULL
);
GO
INSERT INTO dbo.Jobs
VALUES (1, 'F15EAF03-4F45-40E8-85D6-D89B20E00F38', 'Job1')
,(2, NULL, 'Job2')
,(3, 'F15EAF03-4F45-40E8-85D6-D89B20E00F38', 'Job3')
,(4, '3D74F043-2FAC-4C91-8288-13D71C6558C8', 'Job4');
GO
/* *** End DDL and Test Data *** */
/* *** Create Trigger *** */
SET ANSI_NULLS, QUOTED_IDENTIFIER ON;
GO
CREATE TRIGGER dbo.Tasks_TR_U
ON dbo.Tasks
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT, XACT_ABORT ON;
UPDATE T
SET Task = I.Task
,TaskStart = I.TaskStart
,TaskEnd = I.TaskEnd
FROM dbo.Tasks T
JOIN inserted I
ON T.TaskID = I.TaskID
WHERE EXISTS
-- Only QuotationID of NULL allowed
(
SELECT 1
FROM dbo.Jobs J
WHERE J.JobID = T.JobID
AND J.QuotationID IS NULL
)
-- Only update if any changes
AND NOT
(
T.Task = I.Task
AND T.TaskStart = I.TaskStart
AND ISNULL(T.TaskEnd, '1900') = ISNULL(I.TaskEnd, '1900')
);
END
GO
/* *** End Create Trigger *** */
/* Check data in tables. */
select * from dbo.Tasks;
select * from dbo.Jobs;
/* Run test */
UPDATE dbo.Tasks
SET Task = Task + ' Updated'
/* Only JobId = 2 should be updated. */
select * from dbo.Tasks;
/* Drop Test Tables
DROP TABLE dbo.Tasks;
DROP TABLE dbo.Jobs;
*/