在我的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()
仅返回抛出的最后一个错误,我的情况是信息量较少。
使用throw
(THROW)我可以重新引发catch块中的所有bulk insert
错误。但这只是在屏幕上打印出来。
我正在尝试做的事情(我堕落)是将throw
中的此信息存储在变量中,以便之后使用它,例如把它存放在某个地方。
我尝试嵌套try / catch
,但仍然无法将抛出信息转换为变量。我已经阅读了Capturing multiple error messages from a single statement inside TRY CATCH的消息,但我仍然无法实现我的目标。
答案 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