Не возвращается счетчик из вставки, выполненной ExecuteNonQuery против MS SQL Server из сценария PowerShell

Следующий код выполняет BULK INSERT, который завершается успешно, но не возвращает количество затронутых строк. Когда я делаю "SELECT count(*)..." для подтверждения подсчета, были вставлены миллионы строк. Я подозреваю, что ошибка переполнения является частью проблемы. Почему число затронутых строк не возвращается? Любые идеи о том, как получить счет? У меня есть несколько других подобных процедур, и они всегда возвращают счет.

Код

try {

     $Command = New-Object System.Data.SQLClient.SQLCommand
     $Command.Connection = "Persist Security Info=False;Integrated Security=true;Initial Catalog=$($file_info.database);server=$($file_info.db_server_instance)"
     $Command.CommandTimeout = 18000 # 5 hours
     $Command.Connection.Open()

     try {

          $bulkinsert_sql = "BULK INSERT $($file_info.database).$($file_info.owner).$($file_info.table) FROM '$load_file_path' with (ERRORFILE='$load_file_error_path', MAXERRORS=$($file_info.dbload_error_max), TABLOCK, FIELDTERMINATOR='\t')"
          $Command.CommandText = $bulkinsert_sql
          $loaded_cnt=$Command.ExecuteNonQuery()
          write-host "$loaded_cnt ROWS LOADED"

     } catch [System.Data.SqlClient.SqlException] {

          $_ | select -expandproperty invocationinfo | Format-List Line, PositionMessage -force
          write-host $_.Exception.ToString() -foregroundcolor "red"     
          $ErrorActionPreference = "Continue"
     }

     # set error preference back
     $ErrorActionPreference = "stop"

} catch [System.Data.SqlClient.SqlException] {

     $_ | select -expandproperty invocationinfo | Format-List Line, PositionMessage -force
     write-host $_.Exception.ToString() -foregroundcolor "red"
     $ErrorActionPreference = "stop"

} finally {

     if ($Command.Connection -eq 'Open') {
         $Command.Connection.Close()
     }
}

Обнаружены сообщения об ошибках

System.Data.SqlClient.SqlException (0x80131904): Bulk load data conversion error (truncation) for row 1714271, column 72 (PROVIDER_NAME1).
Bulk load data conversion error (truncation) for row 1714272, column 72 (PROVIDER_NAME1).
Bulk load data conversion error (truncation) for row 2083378, column 72 (PROVIDER_NAME1).
Bulk load data conversion error (overflow) for row 4633809, column 82 (TF_ME_TOT_DEDUCTIONS).
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, 
TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean&
 usedCache, Boolean asyncWrite, Boolean inRetry)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at CallSite.Target(Closure , CallSite , Object )
ClientConnectionId:ba9e07ac-1bc4-4c59-8a0a-167d7b281644
Error Number:4863,State:1,Class:16

person Mark    schedule 03.01.2020    source источник
comment
Я читаю о SET ANSI_WARNINGS OFF....   -  person Mark    schedule 04.01.2020
comment
И ALTER DATABASE MyDatabase SET ARITHABORT ON ... но нет решения.   -  person Mark    schedule 04.01.2020
comment
Один ответ показывает ссылку $result = $db.ExecuteWithResults("UPDATE Persons Set City = 'Cavite' where FirstName = 'Miguel'; Select @@ROWCOUNT;") $result.Tables[0].Rows[0] # to output the value of @@rowcount Но я не должен был использовать такой подход.   -  person Mark    schedule 04.01.2020


Ответы (1)


Почему число затронутых строк не возвращается? Любые идеи о том, как получить счет?

ExecuteNonQuery не является методом «самого низкого уровня» для выполнения запроса. Он делает некоторые упрощающие предположения о том, какую информацию может возвращать SQL Server.

При выполнении запроса от клиента SQL Server может возвращать любую комбинацию сообщений об ошибках, сообщений о количестве строк и наборов результатов. Но чтобы упростить работу в обычном случае, SqlClient генерирует исключение SqlException, когда видит сообщение об ошибке, поэтому ExecuteNonQuery даже не возвращает результат (не говоря уже о возвращении количества строк).

Если вы хотите, чтобы ExecuteNonQuery возвращал значение, вы можете перенаправить все сообщения об ошибках в обработчик событий и подавить поведение генерации исключений .NET с помощью SqlConnection.FireInfoMessageEventOnUserErrors.

person David Browne - Microsoft    schedule 04.01.2020
comment
@[Дэвид Браун - Microsoft]SqlConnection.FireInfoMessageEventOnUserErrors также выполняет перенаправление и подавляет? Я посмотрю на это. Есть ли у вас метод более низкого уровня для выполнения таких запросов, который вы предпочитаете или рекомендуете? У меня был довольно хороший успех с ExecuteNonQuery до этого сюрприза. - person Mark; 07.01.2020
comment
FireInfoMessageEventOnUserError подавляет исключения SqlException, возникающие из-за сообщений об ошибках, отправленных с сервера, но не из-за таких вещей, как сетевые ошибки. SqlCommand.ExecuteReader() дает вам доступ к отдельным наборам результатов и количеству строк, а в сочетании с FireInfoMessageEventOnUserError предоставляет API самого низкого уровня, доступный в SqlClient. - person David Browne - Microsoft; 07.01.2020
comment
Да, я заметил, что в документации упоминается. Ошибка с уровнем серьезности 17 или выше, из-за которой сервер прекращает обработку команды, должна обрабатываться как исключение. В этом случае исключение создается независимо от того, как ошибка обрабатывается в событии InfoMessage. Это облом, потому что я хотел бы решить, что делать с идентифицируемыми ошибками. По крайней мере, это моя история.... - person Mark; 07.01.2020
comment
@[David Browne - Microsoft]Еще одна вещь, я думал, что при переполнении произойдет прерывание и откат? Он завершает вставку и терпит неудачу только с одной записью переполнения. Можете ли вы объяснить такое поведение или это отдельный вопрос? - person Mark; 07.01.2020
comment
Другой вопрос. Но это сложно. Прочитайте это: sommarskog.se/error-handling-I.html - person David Browne - Microsoft; 07.01.2020