SQL Server «Продолжить дальше» эквивалент - PullRequest
1 голос
/ 11 сентября 2009

Я работаю над проектом на VB.net, который берет большие текстовые файлы, содержащие T-SQL, и выполняет их для локальной базы данных SQL, но я столкнулся с проблемой в отношении обработки ошибок.

Я использую следующие технологии:

  • VB.net
  • Framework 3.5
  • SQL Express 2005

SQL, который я пытаюсь выполнить, в основном прост, но мое приложение совершенно не знает о схеме или данных, содержащихся в нем. Например:

UPDATE mytable SET mycol2='data' WHERE mycol1=1
INSERT INTO mytable (mycol1, mycol2) VALUES (1,'data')
UPDATE mytable SET mycol2='data' WHERE mycol1=2
INSERT INTO mytable (mycol1, mycol2) VALUES (1,'data')
UPDATE mytable SET mycol2='data' WHERE mycol1=3

Выше приведен пример того, что я выполняю, но эти файлы будут содержать от 10 000 до 20 000 операторов каждый.

Моя проблема заключается в том, что при использовании sqlCommand.ExecuteNonQuery () я получаю исключение, потому что второй оператор INSERT достигнет ограничения первичного ключа в таблице.

Мне нужно знать, что эта ошибка произошла, и регистрировать ее, но также обрабатывать любые последующие операторы. Я попытался обернуть эти операторы в блоки TRY / CATCH, но я не могу найти способ обработать ошибку, а затем продолжить обработку других операторов.

Кажется, что Query Analyzer ведет себя так, но не при использовании sqlCommand.ExecuteNonQuery ().

Так есть ли T-SQL-эквивалент "Resume Next" или какой-то другой способ, которым я могу сделать это без большого количества обработок строк с моей стороны?

Любая помощь с благодарностью.

Ответы [ 7 ]

2 голосов
/ 11 сентября 2009

SQL Server имеет синтаксис Try / Catch. См:

http://msdn.microsoft.com/en-us/library/ms175976.aspx

Чтобы использовать это с вашим файлом, вам придется либо переписать сами файлы, чтобы обернуть каждую строку синтаксисом try / catch, либо ваш код должен будет программно изменять содержимое файла, чтобы обернуть каждую строку.

Не существует эквивалента T-SQL для "On Error Resume Next", и спасибо Ктулху за это.

1 голос
/ 11 сентября 2009

На самом деле ваш пакет выполнен до конца, поскольку нарушения ключа не мешают выполнению пакета. Если вы запустите тот же файл SQL из Management Studio, вы увидите, что в результате все действительные операторы были выполнены, а на панели сообщений содержится ошибка для каждого нарушения ключа. SqlClient из ADO.NEt ведет себя примерно так же, но в конце пакета (когда возвращается SqlCommand.ExecuteNonQuery) он анализирует возвращаемые сообщения и выдает исключение. Исключением является одно единственное SqlException, но его коллекция ошибок содержит SqlError для каждого нарушения ключа, которое произошло.

К сожалению, нет серебряной пули. В идеале файлы SQL не должны вызывать ошибок. Вы можете выбрать итерацию SqlErrors исключения и на индивидуальной основе решить, была ли ошибка серьезной или ее можно игнорировать, зная, что файлы SQL имеют проблемы с качеством данных. Некоторые ошибки могут быть серьезными и не могут быть проигнорированы. См. Серьезность ошибок компонента Database Engine .

Другой альтернативой является явное указание SqlClient не бросать. Если вы установите для свойства FireInfoMessageEventOnUserErrors соединения значение true, оно вызовет событие SqlConnection.InfoMessage , а не перекроет исключение.

1 голос
/ 11 сентября 2009

Рискуя замедлить процесс (сделав тысячи обращений к серверу SQL, а не одному), вы можете решить эту проблему, разбив файл на несколько отдельных запросов, каждый из которых содержит INSERT или UPDATE. Затем вы можете отследить каждую отдельную ошибку по мере ее возникновения и регистрировать ее или устранять, как этого требует ваша бизнес-логика.

0 голосов
/ 12 марта 2018
begin try
 --your critical commands
end try
begin catch
  -- is necessary write somethink like this
  select ''
end cath
0 голосов
/ 11 сентября 2009

Одна из техник, которую я использую, заключается в использовании try / catch и в рамках catch вызывает событие с информацией об исключении. Затем вызывающая сторона может подключить обработчик событий, чтобы сделать с информацией все, что пожелает (зарегистрировать ее, собрать для отправки в пользовательском интерфейсе и т. Д.).

Вы также можете включить метод (используемый во многих областях среды .NET, например, события Windows.Forms и проверка XSD) передачи объекта CancelableEventArgs в качестве второго аргумента события с логическим полем, которое обработчик событий может установить для указания эта обработка должна быть прервана в конце концов.

Еще одна вещь, которую я призываю вас сделать, это подготовить ваши ВСТАВКИ и ОБНОВЛЕНИЯ, а затем вызывать их много раз с различными аргументами.

0 голосов
/ 11 сентября 2009

К сожалению, я не думаю, что есть способ заставить SqlCommand продолжать обработку после возврата ошибки.

Если вы не уверены, вызовет ли какая-либо из команд ошибку или нет (и с некоторыми затратами на производительность), вам следует разделить команды в текстовом файле на отдельные команды SqlCommands ..., что позволит вам использовать попытку / перехватить блок и найти оскорбительные высказывания.

... это, конечно, зависит от команд T-SQL в текстовом файле, каждая из которых должна быть в отдельной строке (или выделена иным образом).

0 голосов
/ 11 сентября 2009

Мне неизвестен способ поддержки возобновления следующего, но один из подходов заключается в том, чтобы использовать локальную переменную таблицы для предотвращения ошибок, например,

Declare @Table table(id int, value varchar(100))
UPDATE mytable SET mycol2='data' WHERE mycol1=1
--Insert values for later usage
INSERT INTO @Table (id, value) VALUES (1,'data')
--Insert only if data does not already exist. 
INSERT INTO mytable (mycol1, mycol2) 
Select id, Value from @Table t left join 
mytable t2 on t.id = t2.MyCol1
where t2.MyCol is null and t.id = 1

EDIT

Хорошо, я не знаю, что я предлагаю это само по себе, но вы могли бы добиться своего рода возобновления следующим образом, заключив цикл try в цикл while, если вы установите условие выхода в конце всех шагов и сохраните отслеживать, какой шаг вы выполнили последним.

Declare @Table table(id int, value varchar(100))

Declare @Step int
set @Step = 0
While (1=1)
Begin

    Begin Try

        if @Step < 1 
        Begin                 
               Insert into @Table  (id, value) values  ('s', 1)
                   Set @Step = @Step + 1
        End
        if @Step < 2
        Begin
            Insert into @Table values ( 1, 's')
                    Set @Step = @Step + 1
        End
        Break
    End Try 
    Begin Catch
      Set @Step = @Step + 1
    End Catch 

End 
Select * from @Table
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...