2016-07-13 2 views
0

Я написал триггер для одной из таблиц нашей компании в SQL Server, который выполняется в UPDATE или INSERT. При работе с INSERT мне нужно вставить две строки в отдельную таблицу. Каждая часть триггера работает нормально, за исключением инструкции INSERT в самом конце. Он не бросает никаких ошибок, SQL Profiler говорит, что INSERT выполнен, и он отлично работает, когда я копирую и вставляю его в свой собственный запрос в SQL Server и заменяю локальные переменные на константы. Но триггер не создает никаких новых строк в таблице, в которую он должен вставляться.Оператор INSERT выполняет, но не создает никаких новых строк?

Мой код ниже:

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: '[email protected]_id 
    WHEN 'INSERTED' THEN 'NEW PART CREATED: '[email protected]_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 '[email protected]_id+' '[email protected]_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="#'[email protected]_color+'"> 
      <tbody> 
       <tr> 
        <td colspan="'[email protected]+'" 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">'[email protected]+'</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 = '[email protected]', @body = @msg, @body_format = 'HTML', @subject = @subject_line, @blind_copy_recipients = '[email protected]', @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 Profiler) без возникновения ошибки, но все же ничего не делать?

+0

SQL Profiler говорит, что INSERT выполнен? Вы уверены, что он проинформирует о вставке в '[DLIDEMO3]. [Dbo]. [USER_DEF_FIELDS]'. вероятно, у вас будет одна из проблем. 1. Профилировщик рассказывает о некоторой вставке, которая встречается в процедуре 'msdb.dbo.sp_send_dbmail @ recipients', или если профайлер действительно говорит о вставке в' DLIDEMO3 '. [Dbo]. [USER_DEF_FIELDS] 'тогда это не должно было бы говорить ложь , вы можете ошибаться при проверке вставки (может быть, смотрите другую таблицу или базу данных) Убедитесь, что ваш взгляд верен – Sami

+1

У вашего триггера есть главный недостаток дизайна. Кажется, вы предполагаете, что только одна строка будет вставлена ​​или обновлена. Это не тот случай. Вы должны сделать этот набор основанным и избавиться от этих скалярных переменных. Я также предлагаю вам не отправлять электронные письма прямо из вашего триггера. Вместо этого создайте промежуточную таблицу и запланированную задачу для сбора данных и отправки электронных писем. –

+0

@Sami, это то, что сказал Профайлер: 'INSERT INTO [DLIDEMO3]. [Dbo].[USER_DEF_FIELDS] \t \t (PROGRAM_ID, удостоверение личности, document_id, DATE_VAL, STRING_VAL) \t \t ЗНАЧЕНИЯ \t \t \t (N'VMPRTMNT», N'UDF-0000023' , @part_id, GETDATE(), NULL), \t \t \t (N'VMPRTMNT 'N'UDF-0000024' , @part_id, NULL, N'NEW ЧАСТЬ СОЗДАННАЯ' + SYSTEM_USER); ' Я дважды проверил таблицу я ищу в, это тот самый. – 7Nate9

ответ

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 гарантирует, что кто-то ввод данных прямо на часовом знаке не встречается с той же проблемой, с которой я столкнулся.)

Это решение действительно делает то, что я пытался сделать с моим предыдущим оператором 10, хотя и пошатнулся на час (что не особенно в этом случае).

Благодарим за конструктивный ввод. :)

Смежные вопросы