Моя цель - выдать исключение обратно вызывающей стороне, но продолжить выполнение хранимой процедуры SQL Server
.Так что, по сути, я пытаюсь выполнить try..catch..finally block
, хотя, насколько мне известно, SQL Server не имеет понятия блока try..catch..finally.
У меня есть примерstored procedure
для иллюстрации.Это просто пример, который я придумал, так что, пожалуйста, не обращайте слишком много внимания на схему таблицы.Надеюсь, вы понимаете суть того, что я пытаюсь осуществить здесь.В любом случае, сохраненный процесс содержит explicit transaction
, который выбрасывает exception
в пределах catch block
.Дальнейшее выполнение после блока try..catch не выполняется, если выполняется THROW
.Насколько я понимаю, по крайней мере в SQL Server THROW не может отличить внутренние и внешние транзакции или вложенные транзакции.
В этой хранимой процедуре у меня есть две таблицы: Tbl1 и Tbl2 . Tbl1 имеет primary key
на Tbl1.ID . Tbl2 имеет foreign key
на EmpFK , который сопоставляется с Tbl1.ID . EmpID имеет уникальное ограничение.Повторные записи не могут быть вставлены в Tbl1 .И Tbl1 и Tbl2 имеют первичный ключ на ID и используют приращение идентификатора для автоматической вставки.Хранимая процедура имеет три входных параметра, один из которых employeeID .
Внутри внутренней транзакции запись вставляется в Tbl1 - новый идентификатор сотрудникадобавлено.В случае неудачи идея заключается в том, чтобы транзакция изящно выдавала ошибку, но сохраненный процесс должен продолжать работать до завершения.Независимо от того, была ли вставка таблицы успешной или неудачной, позже будет использоваться EmpID для заполнения EmpFk .
После блока try..catch я выполняю поиск Tbl1.ID через параметр employeeID , который передается в хранимый процесс.Затем я вставляю запись в TBl2; Tbl1.ID - это значение для Tbl2.EmpFK .
(И вы можете спросить: «Зачем использовать такую схему? Почему бы не объединить в одну таблицу с такимималенький набор данных? »Опять же, это всего лишь пример. Это не обязательно должны быть сотрудники. Вы можете выбрать что угодно. Это всего лишь виджет. Представьте, что Tbl1 может содержать очень, очень большой набор данных.В камне есть две таблицы, которые имеют отношение первичный ключ / внешний ключ.)
Вот пример набора данных:
Tbl1
ID EmpID
1 AAA123
2 AAB123
3 AAC123
Tbl2
ID Role Location EmpFK
1 Junior NW 1
2 Senior NW 2
3 Manager NE 2
4 Sr Manager SE 3
5 Director SW 3
Вот пример хранимой процедуры:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_TestProc]
@employeeID VARCHAR(10)
,@role VARCHAR(50)
,@location VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @employeeFK INT;
BEGIN TRY
BEGIN TRANSACTION MYTRAN;
INSERT [Tbl1] (
[EmpID]
)
VALUES (
@employeeID
);
COMMIT TRANSACTION MYTRAN;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION MYTRAN;
END;
THROW; -- Raises exception, exiting stored procedure
END CATCH;
SELECT
@employeeFK = [ID]
FROM
[Tbl1]
WHERE
[EmpID] = @employeeID;
INSERT [Tbl2] (
[Role]
,[Location]
,[EmpFK]
)
VALUES (
@role
,@location
,@employeeFK
);
END;
Итак, еще раз, я все еще хочу вернуть ошибку вызывающей стороне, то есть зарегистрировать ошибку, но я не хочу, чтобы она остановила выполнение хранимой процедуры в холодном состоянии.Это должно продолжаться очень похоже на блок try..catch..finally.Можно ли это сделать с помощью THROW
или я должен использовать альтернативные средства?
Может быть, я ошибаюсь, но не является THROW
обновленной версией RAISERROR
, и, в дальнейшем, мы должны использовать первоедля обработки исключений?
Я использовал RAISERROR
в прошлом для этих ситуаций, и мне это подходит.Но THROW
- это более простое, элегантное решение, имхо, и, возможно, будет лучшей практикой в будущем.Я не совсем уверен.
Спасибо за вашу помощь заранее.