我正在尝试将excel数据插入sql服务器表中。每列均应使用用户在源Excel中编写的完全相同的格式导入。
我正在使用以下查询来获取数据
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$]')
但是现在在excel的日期列中,我们收到一些浮点值(来自用户的格式问题),如下所示
由于无效数据,OLE提供程序将所有其他日期转换为对应的SQL表列中的浮点值(与每个日期对应的浮点值)。如果将日期列自动强制转换为浮点数,我将无法知道excel文件中数据的原始格式,因此所有列都应作为varchar导入。
如何防止这种数据类型转换?基于谷歌搜索,我已经在连接字符串中使用IMEX = 1来检索混合数据列的数据。 但这是行不通的!
答案 0 :(得分:0)
我认为您应该首先从SQL Server表中获取数据类型以创建记录集,而不是让Excel从工作表中确定数据类型。我相信Excel会根据第一行来决定数据类型,因此在您的情况下,它假定Funded数据是整数,然后将任何后续字符串转换为该数据类型。
这是我使用的完整功能
此代码由我从原始来源(在注释中提到)进行了修改。我进行了更改以更好地处理错误。
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
答案 1 :(得分:-1)
使用SSIS是否有原因?我认为最适合这份工作。
无论如何,回到您的问题。 IMEX=1
是不够的。您需要检查注册表项
您需要在此注册表路径中设置TypeGuessRows
和ImportMixedTypes
(这是针对32位办公室的!):
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Excel
TypeGuessRows = 0 (the default is 8)
ImportMixedTypes = Text
TypeGuessRows
做什么?它尝试根据定义的行数来猜测数据类型。 默认值为8。这意味着它将检查8行以查看应使用哪种数据类型。如果要引擎扫描所有行,请在其中放置 0 。但是有一个问题,如果您的电子表格很大,您可能会为此设置付出沉重的性能损失。
ImportMixedTypes
做什么?这是您的IMEX
设置进入游戏的地方。 IMEX
设置0
,1
,2
共有3种可能的值:
仅在设置IMEX=1
时使用注册表值。 -默认设置为ImportMixedTypes=Text
。对于其他任何值(0、2),都将检查注册表中的值(如果有效),但不会影响结果。 (如果无效,则会出现错误)
ImportMixedTypes
有两个有效值:
ImportMixedTypes=Text
ImportMixedTypes=Majority Type
Majority Type
很少使用。它所做的是计算每列的类型,然后将多数类型用于整个列。 Text
类型会将行大小限制为255个字符,如果要使用更多字符,则必须使用Majority Type
,并且大多数字符必须使用256个以上字符。