问题
I am trying to insert excel data into sql server tables. Each column should be imported with the exact same format that the user wrote in the source Excel.
I am using following query to fetch data
SELECT * FROM OPENROWSET( 'Microsoft.ACE.OLEDB.12.0', 'Excel 12.0 Xml;HDR=YES;IMEX=1;Database=H:\Loadloandata\Test\K3.xlsx',
'SELECT * FROM [Sheet1$]')
But now in the date column of excel we are receiving some float values( format issues from the users) as shown below
Because of the invalid data, the OLE provider convert the all other dates to float values in corresponding SQL table colums (float values corresponding to each date).If a date column is automatically cast to float I won't be able to know the original format of the data in the excel file, so all columns should be imported as varchar.
How can i prevent this datatype conversion? Based on google search i have used IMEX=1 in connection string to retrieve data for mixed data columns. But it is not working !!
回答1:
I think that you should get the data types from the SQL server table first to create the recordset, rather than letting Excel decide the datatypes from the Sheet. I believe Excel decides the data types by the first row, so in your case, it assumed Funded data was an integer, then casts any following strings into that data type.
Here is a full function that I use
This code is modified by me from the original source, which is mentioned in the comment. I made changes to deal with errors better.
Function ExportRangeToSQL(ByVal sourcerange As Range, _
ByVal conString As String, ByVal table As String, _
Optional ByVal beforeSQL = "", Optional ByVal afterSQL As String) As String
'https://www.excel-sql-server.com/excel-sql-server-import-export-using-vba.htm
' Object type and CreateObject function are used instead of ADODB.Connection,
' ADODB.Command for late binding without reference to
' Microsoft ActiveX Data Objects 2.x Library
' ADO API Reference
' https://msdn.microsoft.com/en-us/library/ms678086(v=VS.85).aspx
' Dim con As ADODB.Connection
On Error GoTo Finalise ' throw friendly user connection error
Dim con As Object
Set con = CreateObject("ADODB.Connection")
con.ConnectionString = conString
con.Open
Dim cmd As Object
Set cmd = CreateObject("ADODB.Command")
' BeginTrans, CommitTrans, and RollbackTrans Methods (ADO)
' http://msdn.microsoft.com/en-us/library/ms680895(v=vs.85).aspx
Dim level As Long
level = con.BeginTrans
cmd.CommandType = 1 ' adCmdText
If beforeSQL > "" Then
cmd.CommandText = beforeSQL
cmd.ActiveConnection = con
cmd.Execute
End If
' Dim rst As ADODB.Recordset
Dim rst As Object
Set rst = CreateObject("ADODB.Recordset")
With rst
Set .ActiveConnection = con
.Source = "SELECT * FROM " & table
.CursorLocation = 3 ' adUseClient
.LockType = 4 ' adLockBatchOptimistic
.CursorType = 0 ' adOpenForwardOnly
.Open
' Column mappings
Dim tableFields(100) As Integer
Dim rangeFields(100) As Integer
Dim exportFieldsCount As Integer
exportFieldsCount = 0
Dim col As Integer
Dim index As Variant
For col = 0 To .Fields.Count - 1
index = 0
index = Application.Match(.Fields(col).Name, sourcerange.Rows(1), 0)
If Not IsError(index) Then
If index > 0 Then
exportFieldsCount = exportFieldsCount + 1
tableFields(exportFieldsCount) = col
rangeFields(exportFieldsCount) = index
End If
End If
Next
If exportFieldsCount = 0 Then
Err.Raise 513, , "Column mapping mismatch between source and destination tables"
End If
' Fast read of Excel range values to an array
' for further fast work with the array
Dim arr As Variant
arr = sourcerange.Value
' The range data transfer to the Recordset
Dim row As Long
Dim rowCount As Long
rowCount = UBound(arr, 1)
Dim val As Variant
For row = 2 To rowCount
.AddNew
For col = 1 To exportFieldsCount
val = arr(row, rangeFields(col))
If IsEmpty(val) Then
Else
.Fields(tableFields(col)) = val
End If
Next
Next
.UpdateBatch
End With
rst.Close
Set rst = Nothing
If afterSQL > "" Then
cmd.CommandText = afterSQL
cmd.ActiveConnection = con
cmd.Execute
End If
Finalise:
If con.State <> 0 Then
con.CommitTrans
con.Close
End If
Set cmd = Nothing
Set con = Nothing
' Raise appropriate custom errors
Select Case Err.Number
Case -2147217843
Err.Raise 513, , "Issue connecting to SQL server database - please check login credentials"
Case -2147467259
If InStr(1, Err.Description, "Server does not exist") <> 0 Then
Err.Raise 513, , "Could not connect to SQL server, please check you are connected to the local network (in the office or on VPN)"
Else
Err.Raise 513, , "Issue connecting to SQL server database" & vbNewLine & Err.Description
End If
Case -2147217900
If InStr(1, Err.Description, "'PK_XL_Eng_Projects_QuoteRef'") <> 0 Then
Err.Raise 513, , "Quote already uploaded for this QuoteRef and Upload Time, please wait a minute before trying again" & vbNewLine & vbNewLine & Err.Description
Else
Err.Raise Err.Number, , Err.Description
End If
Case 0
' do nothing no error
Case Else
' re raise standard error
Err.Raise Err.Number, , Err.Description
End Select
End Function
回答2:
Is there a reason why you using SSIS? I think that is best suited for the job.
Anyways, back to your issue. IMEX=1
is not enough. What you need is to check the registry entries
You need set TypeGuessRows
and ImportMixedTypes
within this registry path (this is for 32-bit office!):
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Excel
TypeGuessRows = 0 (the default is 8)
ImportMixedTypes = Text
What does TypeGuessRows
do?
It tries to guess data type based on the number of rows defined. The default values is 8. That means it will check 8 rows to see what data type should be used. If you want to the engine to scan all the rows put 0 there. There is a catch, however, if your spreadsheet large, you could pay heavy performance penalty for such setting.
What does ImportMixedTypes
do?
This is where your IMEX
setting comes into the game. There are 3 possible values for IMEX
setting 0
, 1
, 2
:
- 0 is Export mode
- 1 is Import mode
- 2 is Linked mode (full update capabilities)
Only when setting IMEX=1
the registry value is honored. - with the default setting being ImportMixedTypes=Text
. In any other value (0, 2) the value in registry is checked, if it is valid, but it does not influence the outcome. (you will get an error if invalid)
There are two valid values for ImportMixedTypes
:
ImportMixedTypes=Text
ImportMixedTypes=Majority Type
The Majority Type
is rarely used. What it does it counts type of each column and the majority type is then used for the whole column. The Text
type will limit the row size to 255 characters, if you want to use more characters then Majority Type
must be used and the majority must use more than 256 characters.
来源:https://stackoverflow.com/questions/58099882/import-excel-data-to-sql-server-without-data-conversion