将'throw'输出存储到变量中

时间:2016-01-22 09:25:12

标签: sql-server tsql error-handling bulkinsert

在我的sql Server(2012)中,我有一个bulk insert(在存储的proccedure中)命令,如果出错,可能会产生三个错误。

例如

  

Msg 4864,Level 16,State 1,Line 1
  第8行第1列(id)的批量加载数据转换错误(类型不匹配或指定代码页的无效字符)。

     

Msg 7399,Level 16,State 1,Line 1
  链接服务器“(null)”的OLE DB提供程序“BULK”报告错误。提供商未提供有关错误的任何信息。

     

Msg 7330,Level 16,State 2,Line 1
  无法从OLE DB提供程序“BULK”获取链接服务器“(null)”。

的行

我将此bulk insert包装到try / catch块中以捕获错误,存储错误并重新提升错误。

我正在使用error_message()来获取错误,并raiseerror重新提出错误。在这种情况下的已知问题是error_message()仅返回抛出的最后一个错误,我的情况是信息量较少。

使用throwTHROW)我可以重新引发catch块中的所有bulk insert错误。但这只是在屏幕上打印出来。

我正在尝试做的事情(我堕落)是将throw中的此信息存储在变量中,以便之后使用它,例如把它存放在某个地方。

我尝试嵌套try / catch,但仍然无法将抛出信息转换为变量。我已经阅读了Capturing multiple error messages from a single statement inside TRY CATCH的消息,但我仍然无法实现我的目标。

1 个答案:

答案 0 :(得分:0)

我发现这段代码对于收集所有错误并输出到表非常有用:

DECLARE @Spid varchar(6);
DECLARE @Sql varchar(max);
SELECT @Spid = @@spid
SET @sql = 'CREATE EVENT SESSION [Error Handling Session(' + @spid + ')]
ON SERVER 
ADD EVENT sqlserver.error_reported
(
ACTION(
    sqlserver.session_id,
    sqlserver.sql_text
)
WHERE [package0].[not_equal_unicode_string]([message],N'''''''''''') 
AND [severity]>(10) 
AND [sqlserver].[session_id]=(' + @spid + ')
) 
ADD TARGET package0.ring_buffer
WITH (
  --ALLOW_SINGLE_EVENT_LOSS
  --NO_EVENT_LOSS
  EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
  MAX_MEMORY=4096 KB,
  MAX_DISPATCH_LATENCY=1 SECONDS,
  MAX_EVENT_SIZE=0 KB,
  MEMORY_PARTITION_MODE=NONE,
  TRACK_CAUSALITY=ON,
  STARTUP_STATE=OFF
);

ALTER EVENT SESSION [Error Handling Session(' + @spid + ')] ON SERVER         
STATE=START;';
EXEC(@Sql);

BEGIN TRY
  BACKUP LOG [WrongDBName]
  TO DISK = 'D:\some_destination\that\does\not\exist\NeverGonnaHappen.trn'
  WITH
    NAME = 'Transaction Backup',
    NO_COMPRESSION,
    STATS = 10;    

END TRY
BEGIN CATCH
  DECLARE @XEData XML
  DECLARE @XEName varchar(100) = 'Error Handling Session(' + @spid + ')' 

  SELECT @XEData = CAST(xet.target_data AS XML)
  FROM sys.dm_xe_session_targets AS xet
  JOIN sys.dm_xe_sessions AS xe ON (xe.address = xet.event_session_address)
  WHERE xe.name = @XEName;

  /*
  Check value of "totalEventsProcessed" to ensure events have been 
  dispatched to event session target (ring_buffer).
  If no events have been processed, delay for a period of MAX_DISPATCH_LATENCY +1 (in seconds).
  */
  IF @XEData.value('(/RingBufferTarget/@totalEventsProcessed)[1]', 'INT') = 0
  BEGIN
    WAITFOR DELAY '00:00:02';

    SELECT @XEData = CAST(xet.target_data AS XML)
    FROM sys.dm_xe_session_targets AS xet
    JOIN sys.dm_xe_sessions AS xe
        ON (xe.address = xet.event_session_address)
    WHERE xe.name = @XEName;
  END

  --Comment/uncomment as desired to show the formatted XML session data.
  SELECT @XEData;

  --Shred the XML. Do whatever you want with this data: 
  -- log it to a table, create and send an email alert, etc.
  SELECT 
    x.c.value(N'(@name)[1]', N'NVARCHAR(MAX)') AS EventName,
    x.c.value(N'(@timestamp)[1]', N'datetime') AS EventTime,
    x.c.value(N'(data[@name="error_number"]/value)[1]', N'NVARCHAR(MAX)') AS ErrorNumber,
    x.c.value(N'(data[@name="severity"]/value)[1]', N'NVARCHAR(MAX)') AS Severity,
    x.c.value(N'(data[@name="state"]/value)[1]', N'NVARCHAR(MAX)') AS [State],
    x.c.value(N'(data[@name="user_defined"]/value)[1]', N'NVARCHAR(MAX)') AS UserDefined,
    x.c.value(N'(data[@name="category"]/text)[1]', N'NVARCHAR(MAX)') AS Category,
    x.c.value(N'(data[@name="destination"]/text)[1]', N'NVARCHAR(MAX)') AS Destination,
    x.c.value(N'(data[@name="is_intercepted"]/value)[1]', N'NVARCHAR(MAX)') AS IsIntercepted,
    x.c.value(N'(data[@name="message"]/value)[1]', N'NVARCHAR(MAX)') AS [Message],
    x.c.value(N'(action[@name="sql_text"]/value)[1]', N'NVARCHAR(MAX)') AS SqlText,
    x.c.value(N'(action[@name="session_id"]/value)[1]', N'NVARCHAR(MAX)') AS SessionId
FROM @XEData.nodes('//RingBufferTarget/event') AS x(c)
--Uncomment WHERE to show ONLY those errors that would not be normally logged
--WHERE x.c.value(N'(data[@name="destination"]/text)[1]', N'NVARCHAR(MAX)') = 'USER'

END CATCH;

SET @Sql = 'ALTER EVENT SESSION [Error Handling Session(' + @Spid + ')] ON SERVER STATE=STOP; DROP EVENT SESSION [Error Handling Session(' + @Spid + ')] ON SERVER;';
EXEC(@sql);
GO