我正在从SQL Server 2012数据库将数据导入Excel。我遇到的问题是在Excel中无法一致地识别SQL Server 2012 Date
数据类型列。
如果我使用ADO Recordsets从特定列导入数据,则将列数据类型为Date
或Datetime
的数据作为VBA数据类型String
复制到Recordset中(而不是Date
}或Integer
)。
在Excel中重现Recordset会生成格式为yyyy-mm-dd
的字符串。即使我更改了格式,Excel也不会将这些单元格识别为日期/时间。
然而,当我从另一个单元格引用Excel单元格时,Date
类型被识别(例如:A1包含我的SQL VBA Recordset查询的结果,例如“2013-04-17”。我进入单元格A2“= A1 + 1”,A2将其显示为41382。
但是,当我使用MS Query使用ListObjects和ODBC从同一个数据库中提取数据时,将返回来自同一数据库的相同数据,并且日期由Excel正确解释(即我导入一个名为“Transaction Date”的列, SQL数据类型Datetime
通过MS查询结果将是MS Excel日期“整数”。
如何修改我的VBA Recordset代码,将yyyy-mm-dd
格式的数据视为日期而不是字符串?
谢谢, 约翰
PS:我执行的SQL查询各不相同,有时我从数据类型为“date”的列中获取数据,有时候只是整数或Double数据类型。这意味着难以将“转换(INT,TransactionDate)”硬编入SELECT语句。但是,我是SQL的业余爱好者所以可能有一个超级简单的解决方案(例如,如果我访问数据类型为“DateTime”的列,则SQL应始终发送“CONVERT(DBL,XXX)”而不是XXX,其中XXX是数据类型为DATE的列。
Function GetSQL(strQuery As String) As Variant
Dim rst As ADODB.Recordset
Dim element As Variant
Dim i, j As Integer
Dim v As Variant
On Error GoTo aError
Call ConnecttoDB
cnt.Open
Set rst = New ADODB.Recordset
rst.Open strQuery, cnt, adOpenStatic
rst.MoveFirst
If rst.RecordCount = 0 Then 'i.e. if it's empty
v = CVErr(xlErrNA)
rst.Close
cnt.Close
Else
End If
v = rst.GetRows
For i = 0 To UBound(v, 1)
For j = 0 To UBound(v, 2)
If v(i, j) = -9999 Then
v(i, j) = CVErr(xlErrNA)
Else
End If
Next j
Next i
GetSQL = Application.WorksheetFunction.Transpose(v)
rst.Close
cnt.Close
Exit Function
aError:
MsgBox Err.Description
rst.Close
cnt.Close
End Function
答案 0 :(得分:1)
问题产生于使用Excel函数Transpose而不是循环遍历Recordset结果对象的内容。
在通过Excel进行转置的过程中,Recordset中包含的一些信息(例如eample数据类型)似乎丢失了。这导致日期被Excel解释为字符串。
我猜你的意思是使用循环,而不是使用Excel Transpose函数,因为这样可以避免丢失上述信息。
答案 1 :(得分:0)
ado recodset中的字段类型无法更改,但您尝试过UDT吗?这是一个用户定义类型的简短示例,它将包装ado记录集。然后在您的代码中,您将使用自己的记录集,它将使用Date数据类型。
添加对Microsoft ActiveX数据对象库的引用。
标准模块vba代码:
Private Const CONNECTION_STRING As String = "Provider=sqloledb;Data Source=SQLSERVER2012;Initial Catalog=Test;Integrated Security=SSPI;"
Private Const SQL_QUERY As String = "select * from dbo.DateTest"
Public Type MyRecord
Id As Long
CreatedAt As Date
End Type
Public Sub test()
Dim myRecodset() As MyRecord
myRecodset = GetSQL
End Sub
Public Function GetSQL() As MyRecord()
On Error GoTo aError
Dim adodbConnection As ADODB.Connection
Set adodbConnection = New ADODB.Connection
With adodbConnection
.ConnectionString = CONNECTION_STRING
.CursorLocation = adUseServer
.Open
End With
Dim newRecordset() As MyRecord
Dim newRecord As MyRecord
Dim rowIndex As Long
Dim adodbRecordset As ADODB.Recordset
Set adodbRecordset = New ADODB.Recordset
With adodbRecordset
.Open SQL_QUERY, adodbConnection, adOpenStatic
.MoveFirst
ReDim newRecordset(.RecordCount - 1)
Do While Not .EOF
newRecord.Id = .Fields("Id")
newRecord.CreatedAt = .Fields("CreatedAt")
newRecordset(rowIndex) = newRecord
rowIndex = rowIndex + 1
.MoveNext
Loop
End With
GetSQL = newRecordset
aError:
If (Err.Number <> 0) Then MsgBox Err.Description
adodbRecordset.Close
adodbConnection.Close
End Function
使用此表进行测试:
CREATE TABLE [dbo].[DateTest]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[CreatedAt] [date] NOT NULL
)