Есть утилита, которая осуществляет импорт и экспорт баз данных (MS SQL 2000 и MS SQL 2005).
При экспорте данных все данные из БД выгружаются в файл. При импорте данных вначале производится очистка БД, затем в таблицы загружаются данные из файла.
Импорт осуществляется примерно таким циклом:
- Код: Выделить всё
Recordset.AddNew
For I = 0 To Recordset.Fields.Count - 1
Recordset.Fields(I).Value = ...
Next I
Recordset.Update
При этом, разумеется, возникает ошибка в случае, когда обновляемый столбец является счетчиком (identity).
Проверить это можно с помощью выражения Recordset.Fields(I).Properties("ISAUTOINCREMENT").Value (для счетчика свойство вернет True), однако что с этим делать дальше — непонятно. Я так и не нашел способ, как все-таки заставить записать данные в такое поле.
При загрузке данных с помощью SQL-скрипта есть возможность обойти такое ограничение, указав команду
- Код: Выделить всё
set identity_insert ... on
После этого можно с помощью insert into ... values ... присваивать значения и полям-счетчикам.
Но когда я переделал загрузку на SQL, снова возникли проблемы.
Такой код:
- Код: Выделить всё
cnnDatabase.Execute "set identity_insert [" & D.Tables(C) & "] on", , ADODB.ExecuteOptionEnum.adExecuteNoRecords
SQL = "insert into [" & D.Tables(C) & "] ("
For I = LBound(T.Fields) To UBound(T.Fields)
If I > LBound(T.Fields) Then SQL = SQL & ","
SQL = SQL & "[" & T.Fields(I) & "]"
Next I
SQL = SQL & ")" & vbSQLLine
For ...
rs.AddNew
S = "values ("
For I = LBound(T.Fields) To UBound(T.Fields)
If I > LBound(T.Fields) Then S = S & ","
If IsNull(R.Values(I)) Then
S = S & "null"
Else
Select Case rs.Fields(I).Type
Case adBoolean
S = S & IIf(R.Values(I), "1", "0")
Case adTinyInt, adSmallInt, adInteger, adBigInt
S = S & Trim$(Str$(R.Values(I)))
Case adSingle, adDouble, adNumeric, adDecimal, adCurrency
S = S & Trim$(Str$(R.Values(I)))
Case adDate, adDBDate, adDBTime, adDBTimeStamp
S = S & Format$(R.Values(I), "{\t\s 'yyyy-mm-dd hh:nn:ss'}")
Case adBSTR, adChar, adVarChar, adWChar, adVarWChar, adLongVarChar, adLongVarWChar
S = S & QuoteString(R.Values(I))
Case Else
Stop
S = S & "null"
End Select
End If
Next I
S = S & ")"
cnnDatabase.Execute SQL & S, , ADODB.ExecuteOptionEnum.adExecuteNoRecords Or ADODB.CommandTypeEnum.adCmdText
Next
cnnDatabase.Execute "set identity_insert [" & D.Tables(C) & "] off", , ADODB.ExecuteOptionEnum.adExecuteNoRecords
снова вызывает ошибку, при выполнении cnnDatabase.Execute SQL & S с identity-столбцом выдается ошибка, что подобное возможно только когда identity_insert установлено в ON. Хотя перед началом цикла я это выполнял.
Если все делать одной командой:
- Код: Выделить всё
Connection.Execute "set identity_insert table on " & vbNewLine & "insert into ... values ..." & vbNewLine & set identity_insert table off"
тогда все работает. Но мне бы не хотелось при загрузке каждой строки (а их могут быть сотни тысяч) устанавливать, а затем сбрасывать identity_insert.
Было у меня подозрение, что каким-то образом там включен auto-commit, однако выполнение команды set implicit_transactions off ничего не меняет.
Если нужна еще какая-то информация, то этот вопрос я также задал тут.