我为SQL Server中的一个公司表写了一个触发器,它在UPDATE或INSERT上执行。在处理INSERT时,我需要在一个单独的表中插入两行。除了最后的INSERT语句之外,触发器的每个部分都正常工作。它没有抛出任何错误,SQL Profiler说INSERT执行了,当我将它复制并粘贴到SQL Server自己的查询中并用常量替换局部变量时,它工作正常。但是触发器不会在它应该插入的表中创建任何新行。
我的代码如下:
USE [DLIDEMO3]
GO
/****** Object: Trigger [dbo].[EMAIL_ON_UPDATE] Script Date: 7/13/2016 9:36:40 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[EMAIL_ON_UPDATE]
ON [dbo].[PART]
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @old_part_id nvarchar(30); -- The value of the ID field from before the change (Used to determine if the part existed before the change).
DECLARE @old_description nvarchar(40); -- The value of the DESCRIPTION field before the change.
DECLARE @old_drawing_id nvarchar(30); -- The value of the DRAWING_ID field before the change.
DECLARE @old_drawing_rev_no nvarchar(8); -- The value of the DRAWING_REV_NO field before the change.
DECLARE @old_cust_num nvarchar(80); -- The value of the USER_2 field before the change.
DECLARE @new_description nvarchar(40); -- The value of the DESCRIPTION field after the change.
DECLARE @new_drawing_id nvarchar(30); -- The value of the DRAWING_ID field after the change.
DECLARE @new_drawing_rev_no nvarchar(8); -- The value of the DRAWING_REV_NO field after the change.
DECLARE @new_cust_num nvarchar(80); -- The value of the USER_2 field after the change.
DECLARE @stock_um nvarchar(15); -- The value of the STOCK_UM field after the change.
DECLARE @part_id nvarchar(30); -- The value of the ID field.
DECLARE @product_code nvarchar(15); -- The value of the PRODUCT_CODE field.
DECLARE @status nchar(1); -- The value of the STATUS field.
SELECT
@old_part_id = ID,
@old_description = DESCRIPTION,
@old_drawing_id = DRAWING_ID,
@old_drawing_rev_no = DRAWING_REV_NO,
@old_cust_num = USER_2
FROM deleted;
SELECT
@part_id = ID,
@stock_um = STOCK_UM,
@product_code = PRODUCT_CODE,
@status = STATUS,
@new_description = DESCRIPTION,
@new_drawing_id = DRAWING_ID,
@new_drawing_rev_no = DRAWING_REV_NO,
@new_cust_num = USER_2
FROM inserted;
DECLARE @change_type nvarchar(10) -- Keeps track of what kind of email needs to be sent: UPDATED, INSERTED, or NONE.
SET @change_type = N'NONE';
-- Determines if any of these fields have changed since before the statement executed, and if so, assigns 'UPDATED' to @change_type.
IF ISNULL(@old_description, 'ISNULL') <> ISNULL(@new_description, 'ISNULL')
SET @change_type = N'UPDATED';
IF ISNULL(@old_drawing_id, 'ISNULL') <> ISNULL(@new_drawing_id, 'ISNULL')
SET @change_type = N'UPDATED';
IF ISNULL(@old_drawing_rev_no, 'ISNULL') <> ISNULL(@new_drawing_rev_no, 'ISNULL')
SET @change_type = N'UPDATED';
IF ISNULL(@old_cust_num, 'ISNULL') <> ISNULL(@new_cust_num, 'ISNULL')
SET @change_type = N'UPDATED';
-- Determines if the part ID existed before the statement, and if not, assigns 'INSERTED' to @change_type.
IF ISNULL(@old_part_id, 'ISNULL') = 'ISNULL'
SET @change_type = N'INSERTED';
-- Determines if the part is a raw material, and if not, assigns 'NONE' to @change_type.
IF NOT((@product_code = N'raw' OR @product_code = N'rawotc'))
SET @change_type = N'NONE';
DECLARE @msg varchar(MAX); -- The HTML body of the email to be sent.
DECLARE @subject_line varchar(200); -- The subject line of the email.
DECLARE @title varchar(50); -- The title to be displayed at the top of the table in the email.
DECLARE @bg_color varchar(6); -- The background color of the email.
DECLARE @colspan varchar(1); -- The number of columns in the table in the email.
-- Uses the @change_type to determine @bg_color, resulting in different-colored emails for different kinds of statements.
SET @bg_color =
CASE @change_type
WHEN 'UPDATED' THEN 'FEFFB5'
WHEN 'INSERTED' THEN 'C5E7FF'
ELSE 'FFFFFF'
END;
-- Uses the @change_type to determine @title.
SET @title =
CASE @change_type
WHEN 'UPDATED' THEN 'PART UPDATED: '+@part_id
WHEN 'INSERTED' THEN 'NEW PART CREATED: '+@part_id
ELSE @change_type
END;
-- Uses the @change_type to determine @colspan, since an UPDATED email requires one more column than an INSERTED email does.
SET @colspan =
CASE @change_type
WHEN 'UPDATED' THEN '6'
WHEN 'INSERTED' THEN '5'
ELSE '5'
END;
SET @subject_line = @title;
SET @msg =
'<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
body
{
margin-left: 10px;
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
text-align: center;
}
</style>
</head>
<body>
<div style="font-size: 20px; font-weight: strong; text-align: center;">PART '+@part_id+' '+@change_type+' ON '+CAST(GETDATE() AS varchar(30))+' BY '+SYSTEM_USER+'.<br>';
IF ISNULL(@status, '') = N'O' -- Adds a note stating that the part is obsolete, but only if the part is actually obsolete.
SET @msg = @msg + '<br>***NOTE: THIS PART IS OBSOLETE.***<br>';
SET @msg = @msg +
'</div>
<table width="100%" border="2" cellspacing="5" cellpadding="5" bgcolor="#'+@bg_color+'">
<tbody>
<tr>
<td colspan="'+@colspan+'" align="center" valign="middle" style="font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace; font-weight: bold; font-size: 36px;"><p><!--<img src="/Images/DESLABLGtag3d.png" width="52" height="53" alt=""/>--><span style="font-size: 24px">'+@title+'</span></p></td>
</tr>
<tr>';
IF @change_type = 'UPDATED' -- Adds a column on the left for the 'OLD' and 'NEW' row titles.
SET @msg = @msg + '<td width="10%"></td>';
SET @msg = @msg +
'<td width="30%" height="40" align="middle" valign="middle" style="font-weight: bold;">DESCRIPTION</td>
<td width="15%" height="40" align="middle" valign="middle" style="font-weight: bold;">UoM</td>
<td width="15%" height="40" align="middle" valign="middle" style="font-weight: bold;">CUST #</td>
<td width="15%" height="40" align="middle" valign="middle" style="font-weight: bold;">DRAWING</td>
<td width="15%" height="40" align="middle" valign="middle" style="font-weight: bold;">DRAWING REV #</td>
</tr>
<tr>';
IF @change_type = 'UPDATED'
SET @msg = @msg + '<td width="10%" height="40" align="middle" valign="middle" style="font-weight: bold;">NEW</td>';
SET @msg = @msg +
'<td width="30%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@new_description,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@stock_um,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@new_cust_num,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@new_drawing_id,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@new_drawing_rev_no,'')+'</td>
</tr>';
IF @change_type = 'UPDATED'
SET @msg = @msg +
'<tr>
<td width="10%" height="40" align="middle" valign="middle" style="font-weight: bold;">OLD</td>
<td width="30%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@old_description,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@stock_um,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@old_cust_num,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@old_drawing_id,'')+'</td>
<td width="15%" height="40" align="left" valign="middle" bgcolor="#E5E5E5" style="font-size: 16px; font-family: Consolas, ''Andale Mono'', ''Lucida Console'', ''Lucida Sans Typewriter'', Monaco, ''Courier New'', monospace;">'+ISNULL(@old_drawing_rev_no,'')+'</td>
</tr>';
SET @msg = @msg +
'</tbody>
</table>
</body>
</html>';
-- Sends an email only if @change_type is 'INSERTED' or 'UPDATED'.
IF @change_type <> 'NONE'
EXEC msdb.dbo.sp_send_dbmail @recipients = 'example@email.com', @body = @msg, @body_format = 'HTML', @subject = @subject_line, @blind_copy_recipients = 'generic@email.com', @profile_name = 'SQLProfile';
IF @change_type = 'INSERTED'
INSERT INTO [DLIDEMO3].[dbo].[USER_DEF_FIELDS]
(PROGRAM_ID, ID, DOCUMENT_ID, DATE_VAL, STRING_VAL)
VALUES
(N'VMPRTMNT', N'UDF-0000023', @part_id, GETDATE(), NULL),
(N'VMPRTMNT', N'UDF-0000024', @part_id, NULL, N'NEW PART CREATED BY '+SYSTEM_USER);
END
我做错了什么? INSERT如何执行(根据SQL事件探查器)而不会产生错误,但仍然没有做任何事情?
答案 0 :(得分:0)
在一些技术支持的帮助下,我设法找到了一个可行的解决方案(虽然没有像我希望的那样立即或优雅)。
事实证明,激活此触发器的一批语句包含一个UPDATE
语句,该语句撤消了触发器INSERT
语句所做的更改,因此我决定使用临时表和预定工作,以确保声明之间的时间分离。
我创建了一个新表:
USE [DLIDEMO3]
GO
CREATE TABLE [dbo].[DLI_STAGING_RAWS](
[PROGRAM_ID] [nvarchar](30) NOT NULL,
[ID] [nvarchar](30) NOT NULL,
[DOCUMENT_ID] [nvarchar](128) NULL,
[DATE_VAL] [datetime] NULL,
[STRING_VAL] [nvarchar](128) NULL,
[CREATE_DATETIME] [datetime] NOT NULL
) ON [PRIMARY]
GO
我将触发器中的INSERT
语句更改为:
INSERT INTO [DLIDEMO3].[dbo].[DLI_STAGING_RAWS]
(PROGRAM_ID, ID, DOCUMENT_ID, DATE_VAL, STRING_VAL, CREATE_DATETIME)
VALUES
(N'VMPRTMNT', N'UDF-0000023', @part_id, GETDATE(), NULL, GETDATE()),
(N'VMPRTMNT', N'UDF-0000024', @part_id, NULL, N'NEW PART CREATED BY '+SYSTEM_USER, GETDATE());
我按照以下命令创建了一个每小时执行一次的预定作业:
WHILE EXISTS (SELECT * FROM [DLIDEMO3].[dbo].[DLI_STAGING_RAWS])
BEGIN
DECLARE
@program_id nvarchar(30),
@id nvarchar(30),
@document_id nvarchar(128),
@date_val datetime,
@string_val nvarchar(250),
@create_datetime datetime;
SELECT TOP 1
@program_id = PROGRAM_ID,
@id = ID,
@document_id = DOCUMENT_ID,
@date_val = DATE_VAL,
@string_val = STRING_VAL,
@create_datetime = CREATE_DATETIME
FROM [DLIDEMO3].[dbo].[DLI_STAGING_RAWS]
ORDER BY ID ASC;
IF DATEDIFF(mi, @create_datetime, GETDATE()) >= 15
BEGIN
INSERT INTO [DLIDEMO3].[dbo].[USER_DEF_FIELDS]
(PROGRAM_ID, ID, DOCUMENT_ID, DATE_VAL, STRING_VAL)
VALUES
(@program_id, @id, @document_id, @date_val, @string_val);
DELETE FROM [DLIDEMO3].[dbo].[DLI_STAGING_RAWS]
WHERE PROGRAM_ID = @program_id AND ID = @id AND DOCUMENT_ID = @document_id;
END;
END;
(DATEDIFF
条件确保有人在小时标记处输入数据时不会遇到我遇到的完全相同的问题。)
这个解决方案基本上与我之前的INSERT
声明有关,尽管错开了一个小时(在这种情况下并不特别重要)。
感谢所有建设性的意见。 :)