简体   繁体   English

SQL Server触发器锁定表

[英]SQL Server trigger locks table

I'm not very versed in writing SQL, but I'm attempting to implement a trigger after INSERT. 我不是很精通SQL编写,但是我尝试在INSERT之后实现触发器。

The trigger will fire, however, the more complicated this particular SELECT statement gets it seems that it locks the table. 触发器将触发,但是,此特定的SELECT语句看起来似乎更锁定了表,因此变得更加复杂。 If I simplify the statement to only have a couple of argument it runs fine. 如果我将语句简化为仅包含几个参数,则可以正常运行。

If I run the SELECT statement from SSMS, it works, and if I run it from Visual Studio in the VB.net application, it also works. 如果我从SSMS运行SELECT语句,则它可以工作,如果我从VB.net应用程序的Visual Studio运行它,则它也可以工作。 I've tried increasing the command timeout but it still fails. 我尝试增加命令超时,但仍然失败。 There are only a few rows of data in the table. 表中只有几行数据。

Any insight would be greatly appreciated. 任何见识将不胜感激。 Please let me know if more detail is required. 如果需要更多详细信息,请告诉我。 This is a payroll timeclock table, I'm triggering when a record is inserted and then grabbing the previous days clock out date (so I can compare the previous days payroll hours to the previous days project hours). 这是工资表时间表,我在插入记录时触发,然后获取前几天的上班时间(因此,我可以将前几天的工资时数与前几天的项目时数进行比较)。

I forgot to mention that I'm running the SELECT statement on a view I created that includes two tables from the native application. 我忘了提一下,我正在创建的包含本地应用程序中两个表的视图上运行SELECT语句。

SELECT TOP 1
    @LastDateClockOut = datEvent
FROM 
    MyTable.dbo.TimeMTSView
WHERE 
    datEvent < @Today 
    AND strUniqueID = @nUser 
    AND blnEventType = 0 
    AND lngClassificationID = 0
ORDER BY 
    datEvent DESC;

Here is the entire trigger: 这是整个触发器:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[trgAfterInsert] 
ON [dbo].[tblTimes]
AFTER INSERT
AS
    DECLARE @trg_lngClassificationID int;

    SELECT @trg_lngClassificationID = i.lngClassificationID 
    FROM inserted i;

    IF (@trg_lngClassificationID = 0) --If the date Classification is 0 this means it is NORMAL time as opposed to VACATION or HOLIDAY

    DECLARE @trg_lngID int;
    DECLARE @trg_lngEmployeeID varchar(20);
    DECLARE @trg_blnEventType bit;
    DECLARE @blnEventChar nvarchar(1);
    DECLARE @trg_datEvent datetime;
    DECLARE @nUser varchar(255);
    DECLARE @cmd varchar(255);
    DECLARE @Today varchar(255);
    DECLARE @LastDateClockOut datetime;
    DECLARE @strLastClock varchar(255);

    SELECT @trg_lngID = i.lngID FROM inserted i;
    SELECT @trg_lngEmployeeID = i.lngEmployeeID FROM inserted i;
    SELECT @trg_blnEventType = i.blnEventType FROM inserted i;
    SELECT @trg_datEvent = i.datEvent FROM inserted i;

    SELECT @nUser = strUniqueID 
    FROM dbo.tblEmployees 
    WHERE lngID = @trg_lngEmployeeID AND blnDeleted = 0

    SELECT @blnEventChar = CONVERT(NVARCHAR, @trg_blnEventType);
    SELECT @Today = CONVERT(VARCHAR, GetDate(), 103);

    SELECT TOP 1 @LastDateClockOut = datEvent 
    FROM MyTable.dbo.TimeMTSView 
    WHERE datEvent < @Today 
      AND strUniqueID = @nUser 
      AND blnEventType = 0 
      AND lngClassificationID = 0 
    ORDER BY datEvent DESC --This is what fails

    SELECT @strLastClock = CONVERT(VARCHAR, @LastDateClockOut, 103);

    -- Grab the path to the TimeMTSTrigger.exe written out by the application itself to a log file:
    DECLARE @FileContents  VARCHAR(MAX)

    SELECT @FileContents = BulkColumn
    FROM OPENROWSET(BULK'C:\MTSPath\MTSPath.sql', SINGLE_BLOB) x;

    SET @cmd = 'Start ' + @FileContents + ' ' + @nUser + ' ' + @blnEventChar + ' ' + @strLastClock
    EXEC xp_cmdshell @cmd

I was able to resolve this by not running the SELECT statement on the View I had created in a separate database. 通过不在单独数据库中创建的View上运行SELECT语句,可以解决此问题。

The View had combined two tables from the TIMECLOCKMTS database just to make it easier to grab data. 视图将TIMECLOCKMTS数据库中的两个表合并在一起,只是为了更轻松地获取数据。 However, the SELECT statement on the View would not run in the SQL Trigger or the exe itself, both would hang and timeout. 但是,视图上的SELECT语句无法在SQL触发器或exe本身中运行,都将挂起并超时。

By eliminating the View from both the Trigger and EXE and only referencing tables in the Trigger's database this runs perfectly: 通过从触发器和EXE消除视图,并且仅引用触发器数据库中的表,可以完美运行:

USE [TIMECLOCKMTS]
GO
/****** Object:  Trigger [dbo].[trgAfterInsert]    Script Date: 5/19/2018 2:22:34 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[trgAfterInsert] ON [dbo].[tblTimes]
AFTER INSERT
AS

declare @trg_lngClassificationID int;
SELECT @trg_lngClassificationID=i.lngClassificationID from inserted i;

IF (@trg_lngClassificationID = 0) --If the date Classification is 0 this means it is NORMAL time as opposed to VACATION or HOLIDAY
declare @trg_lngID int;
declare @trg_lngEmployeeID varchar(20);
declare @trg_blnEventType bit;
declare @blnEventChar nvarchar(1);
declare @trg_datEvent datetime;
declare @nUser varchar(255);
declare @cmd varchar(255);
declare @Today varchar(255);
declare @LastDateClockOut datetime;

SELECT @trg_lngID=i.lngID from inserted i;
SELECT @trg_lngEmployeeID=i.lngEmployeeID from inserted i;
SELECT @trg_blnEventType=i.blnEventType from inserted i;
SELECT @trg_datEvent=i.datEvent from inserted i;
SELECT @nUser = strUniqueID FROM dbo.tblEmployees WHERE lngID = @trg_lngEmployeeID AND blnDeleted = 0
SELECT @blnEventChar = CONVERT(NVARCHAR, @trg_blnEventType);

--Grab the path to the TimeMTSTrigger.exe written out by the application itself to a log file:
DECLARE @FileContents  VARCHAR(MAX)
SELECT @FileContents=BulkColumn
FROM   OPENROWSET(BULK'C:\MTSPath\MTSPath.sql',SINGLE_BLOB) x;

SET @cmd = 'Start ' + @FileContents + ' ' + @nUser + ' ' + @blnEventChar + ' ' + @trg_lngEmployeeID
EXEC xp_cmdshell @cmd

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM