2010-04-26 3 views
6

У меня есть скрипт sql, который настроен на roll to production. Я объединил различные проекты в отдельные транзакции. В каждой транзакции мы создали хранимые процедуры. Я получаю сообщения об ошибкахTSQL - создать хранимую процедуру внутри оператора транзакции

Msg 156, Level 15, State 1, Line 4 Неверный синтаксис рядом с ключевым словом «procedure».

Я создал этот пример сценарий для иллюстрации

Begin Try 
Begin Transaction 
    -- do a bunch of add/alter tables here 
    -- do a bunch of data manipulation/population here 

    -- create a stored proc 
    create procedure dbo.test 
    as 
    begin 
    select * from some_table 
    end 
Commit 
End Try 
Begin Catch 
    Rollback 
    Declare @Msg nvarchar(max) 
    Select @Msg=Error_Message(); 
    RaisError('Error Occured: %s', 20, 101,@Msg) With Log; 
End Catch 

ошибка, кажется, подразумевает, что я не могу создавать хранимые проки внутри транзакции, но я не нахожу никаких документов, которые говорят иначе (возможно, Google ISN Сегодня не бывает.

+0

это для сервера sql? –

+0

Да, извините, я должен был упомянуть об этом. sql 2008. –

+0

Я решил вытащить процесс создания из транзакции и попробовать/уловить в свой раздел. Я положил оператор «if exists then drop» и добавил «статусы (если есть), чтобы напечатать сообщение» вокруг сохраненного создания proc. Спасибо за все отзывы, я кое-что узнал от него. –

ответ

10

попробовать делает create procedure в EXEC('...'), как это:

Begin Try 
Begin Transaction 
    -- do a bunch of add/alter tables here 
    -- do a bunch of data manipulation/population here 

    -- create a stored proc 
    EXEC ('create procedure dbo.test 
    as 
    begin 
    select * from some_table 
    end') 
Commit 
End Try 
Begin Catch 
    Rollback 
    Declare @Msg nvarchar(max) 
    Select @Msg=Error_Message(); 
    RaisError('Error Occured: %s', 20, 101,@Msg) With Log; 
End Catch 

GO 
+3

+1. Это нужно сделать, поскольку вызов 'create procedure ...' должен быть первым в скрипте. Ввод его в свою партию с помощью «EXEC'» разрешает это. Это также можно использовать для создания файлов сценариев, которые создают или обновляют хранимую процедуру. Очень полезно для архивирования сценариев процедур. –

+0

В примере, если вы запустили его непосредственно (помещаете в реальное имя таблицы для some_table), когда материал ddl/dml закомментировал ошибку, все еще происходит ошибка, и все же процедура создания является первым утверждением или я не понимаю. –

+0

код работает отлично для меня, я не уверен, что вы меняете –

0

я припоминаю, вы не можете делать такие вещи, как создавать, изменять или удалять схемы базы данных объектов — включая хранимые процедуры — внутри транзакции (так как такая структурная изменения не являются транзакционными: вы не можете откатить их с изменениями данных).

+1

Я проверил код из моего ответа, он не только создает хранимую процедуру, но и если вы заставляете ROLLBACK в коде, он также откатывается обратно. –

+1

@KM: Конечно, это могло быть изменено в более поздних версиях SQL Server. – Richard

10

Вы не можете написать свой сценарий таким образом, поскольку существует множество операторов, которые должны запускаться в их собственной партии. Вместо этого, я рекомендовал бы делать что-то похожее на SQL, как Red-Gate Сравним строит свои сценарии:

Set Xact_Abort On 
GO 
Begin Transaction 
GO 
If object_id('tempdb..#tmpErrors') is not null 
    Drop Table #tmpErrors 
GO 
Create Table #tmpErrors([Error] int not null) 
GO 
Create Procedure dbo.Test 
As 
Begin 
    --.... 
End 
GO 
If @@Error <> 0 AND @@TranCount >0 Rollback Transaction 
GO 
IF @@TranCount = 0 Begin Insert #tmpErrors (Error) Select 1 Begin Transaction End 
GO 

-- more statements 

GO 
If @@Error <> 0 AND @@TranCount >0 Rollback Transaction 
GO 
IF @@TranCount = 0 Begin Insert #tmpErrors (Error) Select 1 Begin Transaction End 
GO 

--..... 

IF NOT EXISTS(SELECT * FROM #tmpErrors) 
    BEGIN 
     PRINT 'The database update succeeded' 
     IF @@TRANCOUNT > 0 COMMIT TRANSACTION 
    END 
ELSE 
    BEGIN 
     PRINT 'The database update failed' 
     IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION 
    END 
GO 

DROP TABLE #tmpErrors 
GO 
+0

SSMS жалуется, что 'Error' не является столбцом в' #tmpErrors (Error). Выберите 1', если это будет 'ID' (или' Create Table #tmpErrors (Id int not null) 'должно быть' Create Table #tmpErrors (Ошибка int not null) '? –

+0

@SamHolder - Да, это опечатка с моей стороны, которую я исправил. Если вы идете с' Id', то оператор Create Table должен явно использовать 'Id'. Если вы идете с' Error', то для этого необходимо обновить инструкцию Create Table. – Thomas

+0

Спасибо за разъяснение. +1 от меня. Отличный ответ. –

2

Существуют различные проблемы, связанные с решением, предложенным КМ:

  • Если содержание того, что вы поместить в ваш вызов EXEC() неверно семантически (например, вы положили несуществующую таблицу в FROM внутри хранимой процедуры), что ошибка не пузырится и транзакция не откат.

  • Если содержимое того, что вы помещаете в ваш вызов EXEC(), является синтаксически неправильным (например, вы помещаете SELECTT вместо SELECT внутри хранимой процедуры), транзакция кажется откатанной, но полностью критическая ошибка пузырится вверх :

    A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The specified network name is no longer available.) 
    

Так что я до сих пор в убыток, как создать процедуру внутри транзакции, но до сих пор сделка и попытка прилов быть полезным.

+0

Используйте блок CATCH, который находится в ответе Майл: http://stackoverflow.com/questions/180075/executing-a-stored-procedure-inside -begin-конец транзакции – knocte

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