SQL VBA 中的查询输出与 SQL Oracle 中的不同
SQL Query output in VBA is different than in SQL Oracle
VBA 有问题。我已经编写了 sql 代码(300 行),它在 SQL 中运行完美,输出为:
Line Number Date Employee PN Tax
1 1111 2015-10-15 AP 6225-6 L1
2 1111 2015-10-15 AP 6225-6 L2
3 1111 2015-10-15 (null) CHARGE (null)
4 1111 2015-10-15 AP 55555 L2
我已将这么大的 sql 插入到我的 VBA 代码中,但出于某种原因,它与我在 ORACLE 中看到的不完全匹配。
我在 VBA 中看到的是这个(不同的第 3 行):
Line Number Date Employee PN Tax
1 1111 2015-10-15 AP 6225-6 L1
2 1111 2015-10-15 AP 6225-6 L2
3 1111 (null) (null) 6225 (null)
4 1111 2015-10-15 AP 55555 L2
由于某种原因和某种原因,SQL 工作方式不同,在 VBA 中没有提供所需的输出。什么会导致这个问题???毫无头绪,因为我在 VBA 中写了两次 SQL 以防万一我认为是我的错误。
我的VBA代码:
Sub Update_table_and_data()
'sql failo suformavimas
Dim con As ADODB.Connection
Dim rec As ADODB.Recordset
Dim cmd As ADODB.Command
Dim sql As String
sql = "Driver={Microsoft ODBC for Oracle}; " & _
"CONNECTSTRING=(DESCRIPTION=" & _
"(ADDRESS=(PROTOCOL=TCP)" & _
"(HOST= ODB)(PORT=1525))" & _
"(CONNECT_DATA=(SERVICE_NAME=ABTL))); uid=ID; pwd=PWD;"
dat1 = (Sheets("Data").Cells(2, "G"))
dat2 = (Sheets("Data").Cells(2, "H"))
Set con = New ADODB.Connection
Set rec = New ADODB.Recordset
Set cmd = New ADODB.Command
Sheets("Output").Range("A2:AS999999").ClearContents
If ((Not IsEmpty(dat1)) And (Not IsEmpty(dat2))) Then
con.Open sql
Set rec = con.Execute(" SELECT distinct ........
' " WHERE i.date >= to_date('" & dat1 & "','YYYY.MM.DD')
' " AND i.date <= to_date('" & dat2 & "','YYYY.MM.DD' ) ) XX order by XX.number ")
If Not rec.EOF Then
Sheets("Output").Range("A2").CopyFromRecordset rec
rec.Close
Else
MsgBox "PLEASE, CHECK DATE FORMAT!", vbCritical
End If
If CBool(con.State And adStateOpen) Then con.Close
Set rec = Nothing
Set con = Nothing
End Sub
问题是这两个查询不相同。
您的 VBA 版本中有以下内容,但 Oracle 版本中没有:
WHERE inh.invoice_date >= to_date('" & dat1 & "','YYYY.MM.DD')
AND inh.invoice_date <= to_date('" & dat2 & "','YYYY.MM.DD' ) ) XX
可能还有其他差异,但我立即跳出来了。
问题是 CopyFromRecordset
- 它 运行 匹配 255 个字符,而且它不是唯一的 Excel.Range 方法。
问题是:我有没有方法?在您进入写入范围阶段之前,您是否有一个 OLEDB 驱动程序对您的 Recordset 执行此操作?
您应该在 VBA 中遍历您的记录集,并检查 VBA 中的违规字段 是否存在长度超过 255 个字符的值。如果字段已被 t运行 分类,请尝试在连接字符串中使用本机 Oracle 客户端驱动程序,而不是 Microsoft Oracle OLEDB 提供程序 - Connections.com 将提供信息。
一旦您知道记录集实际上包含您的数据,没有 t运行cation,请再次尝试 CopyFromRecordset。我其实不希望它写一个长度超过255个字符的字段,但是我遇到这个错误已经有一段时间了,它可能已经被修复了,给悲观主义者一个惊喜总是好的。
下一步:
A VBA 替代 CopyFromRecordset
这里有三个任务:
- 使用数据填充 VBA 数组变体
Recordset.GetRows()
;
- 转置数组,因为 GetRows 是错误的方法
Excel;
- 调整目标范围并将数组写为
Range.Value = Array
,一项重复性任务
应该在 ArrayToRange() 例程中自动执行。
...可能还需要一些辅助工作来编写字段名称,但我在简短的回答中忽略了这一点。
最终结果是你运行这段代码:
ArrayToRange rngTarget, ArrayTranspose(rst.GetRows)<BR />
转置数组很简单,但无论如何:
Public Function ArrayTranspose(InputArray As Variant) As Variant
Application.Volatile False<BR />
Dim arrOutput As Variant<BR />
Dim i As Long
Dim j As Long
Dim iMin As Long
Dim iMax As Long
Dim jMin As Long
Dim jMax As Long<BR />
iMin = LBound(InputArray, 1)
iMax = UBound(InputArray, 1)
jMin = LBound(InputArray, 2)
jMax = UBound(InputArray, 2)<BR />
ReDim arrOutput(jMin To jMax, iMin To iMax)<BR />
For i = iMin To iMax
For j = jMin To jMax
arrOutput(j, i) = InputArray(i, j)
Next j
Next i<BR />
ArrayTranspose = arrOutput<BR />
End Function<BR />
...如果您不在目标单元格中添加数组维度检查和保留公式,那么 ArrayToRange 是微不足道的:要点是如果范围的维度完全正确,您可以将数据写入单个 'hit'匹配数组的维度:
Public Sub ArrayToRange(rngTarget As Excel.Range, InputArray As Variant)
' Write an array to an Excel range in a single 'hit' to the sheet
' InputArray should be a 2-Dimensional structure of the form Variant(Rows, Columns)
' The target range is resized automatically to the dimensions of the array, with
' the top left cell used as the start point.
' This subroutine saves repetitive coding for a common VBA and Excel task.
' Author: Nigel Heffernan http://Excellerando.blogspot.com
On Error Resume Next
Dim rngOutput As Excel.Range
Dim iRowCount As Long
Dim iColCount As Long
iRowCount = UBound(InputArray, 1) - LBound(InputArray, 1)
iColCount = UBound(InputArray, 2) - LBound(InputArray, 2)
With rngTarget.Worksheet
Set rngOutput = .Range(rngTarget.Cells(1, 1), _
rngTarget.Cells(iRowCount + 1, iColCount + 1))
Application.EnableEvents = False
rngOutput.Value2 = InputArray
Application.EnableEvents = True
Set rngTarget = rngOutput ' resizes the range This is useful, most of the time
End With ' rngTarget.Worksheet
End Sub
注意事项:在旧版本的 Excel(Office 2000,如果我记得的话)中,数组 'write' 仍然 t运行 为 255 个字符。这不再是问题;如果您仍在使用 XL2000,包含超过 255 个字符的字符串的单元格就已经是一个问题,您可能会对 t运行cation.
感到高兴
VBA 有问题。我已经编写了 sql 代码(300 行),它在 SQL 中运行完美,输出为:
Line Number Date Employee PN Tax
1 1111 2015-10-15 AP 6225-6 L1
2 1111 2015-10-15 AP 6225-6 L2
3 1111 2015-10-15 (null) CHARGE (null)
4 1111 2015-10-15 AP 55555 L2
我已将这么大的 sql 插入到我的 VBA 代码中,但出于某种原因,它与我在 ORACLE 中看到的不完全匹配。
我在 VBA 中看到的是这个(不同的第 3 行):
Line Number Date Employee PN Tax
1 1111 2015-10-15 AP 6225-6 L1
2 1111 2015-10-15 AP 6225-6 L2
3 1111 (null) (null) 6225 (null)
4 1111 2015-10-15 AP 55555 L2
由于某种原因和某种原因,SQL 工作方式不同,在 VBA 中没有提供所需的输出。什么会导致这个问题???毫无头绪,因为我在 VBA 中写了两次 SQL 以防万一我认为是我的错误。
我的VBA代码:
Sub Update_table_and_data()
'sql failo suformavimas
Dim con As ADODB.Connection
Dim rec As ADODB.Recordset
Dim cmd As ADODB.Command
Dim sql As String
sql = "Driver={Microsoft ODBC for Oracle}; " & _
"CONNECTSTRING=(DESCRIPTION=" & _
"(ADDRESS=(PROTOCOL=TCP)" & _
"(HOST= ODB)(PORT=1525))" & _
"(CONNECT_DATA=(SERVICE_NAME=ABTL))); uid=ID; pwd=PWD;"
dat1 = (Sheets("Data").Cells(2, "G"))
dat2 = (Sheets("Data").Cells(2, "H"))
Set con = New ADODB.Connection
Set rec = New ADODB.Recordset
Set cmd = New ADODB.Command
Sheets("Output").Range("A2:AS999999").ClearContents
If ((Not IsEmpty(dat1)) And (Not IsEmpty(dat2))) Then
con.Open sql
Set rec = con.Execute(" SELECT distinct ........
' " WHERE i.date >= to_date('" & dat1 & "','YYYY.MM.DD')
' " AND i.date <= to_date('" & dat2 & "','YYYY.MM.DD' ) ) XX order by XX.number ")
If Not rec.EOF Then
Sheets("Output").Range("A2").CopyFromRecordset rec
rec.Close
Else
MsgBox "PLEASE, CHECK DATE FORMAT!", vbCritical
End If
If CBool(con.State And adStateOpen) Then con.Close
Set rec = Nothing
Set con = Nothing
End Sub
问题是这两个查询不相同。
您的 VBA 版本中有以下内容,但 Oracle 版本中没有:
WHERE inh.invoice_date >= to_date('" & dat1 & "','YYYY.MM.DD')
AND inh.invoice_date <= to_date('" & dat2 & "','YYYY.MM.DD' ) ) XX
可能还有其他差异,但我立即跳出来了。
问题是 CopyFromRecordset
- 它 运行 匹配 255 个字符,而且它不是唯一的 Excel.Range 方法。
问题是:我有没有方法?在您进入写入范围阶段之前,您是否有一个 OLEDB 驱动程序对您的 Recordset 执行此操作?
您应该在 VBA 中遍历您的记录集,并检查 VBA 中的违规字段 是否存在长度超过 255 个字符的值。如果字段已被 t运行 分类,请尝试在连接字符串中使用本机 Oracle 客户端驱动程序,而不是 Microsoft Oracle OLEDB 提供程序 - Connections.com 将提供信息。
一旦您知道记录集实际上包含您的数据,没有 t运行cation,请再次尝试 CopyFromRecordset。我其实不希望它写一个长度超过255个字符的字段,但是我遇到这个错误已经有一段时间了,它可能已经被修复了,给悲观主义者一个惊喜总是好的。
下一步:
A VBA 替代 CopyFromRecordset
这里有三个任务:
- 使用数据填充 VBA 数组变体
Recordset.GetRows()
; - 转置数组,因为 GetRows 是错误的方法 Excel;
- 调整目标范围并将数组写为
Range.Value = Array
,一项重复性任务 应该在 ArrayToRange() 例程中自动执行。
...可能还需要一些辅助工作来编写字段名称,但我在简短的回答中忽略了这一点。
最终结果是你运行这段代码:
ArrayToRange rngTarget, ArrayTranspose(rst.GetRows)<BR />
转置数组很简单,但无论如何:
Public Function ArrayTranspose(InputArray As Variant) As Variant
Application.Volatile False<BR />
Dim arrOutput As Variant<BR />
Dim i As Long
Dim j As Long
Dim iMin As Long
Dim iMax As Long
Dim jMin As Long
Dim jMax As Long<BR />
iMin = LBound(InputArray, 1)
iMax = UBound(InputArray, 1)
jMin = LBound(InputArray, 2)
jMax = UBound(InputArray, 2)<BR />
ReDim arrOutput(jMin To jMax, iMin To iMax)<BR />
For i = iMin To iMax
For j = jMin To jMax
arrOutput(j, i) = InputArray(i, j)
Next j
Next i<BR />
ArrayTranspose = arrOutput<BR />
End Function<BR />
...如果您不在目标单元格中添加数组维度检查和保留公式,那么 ArrayToRange 是微不足道的:要点是如果范围的维度完全正确,您可以将数据写入单个 'hit'匹配数组的维度:
Public Sub ArrayToRange(rngTarget As Excel.Range, InputArray As Variant) ' Write an array to an Excel range in a single 'hit' to the sheet ' InputArray should be a 2-Dimensional structure of the form Variant(Rows, Columns)
' The target range is resized automatically to the dimensions of the array, with ' the top left cell used as the start point.
' This subroutine saves repetitive coding for a common VBA and Excel task.
' Author: Nigel Heffernan http://Excellerando.blogspot.com
On Error Resume Next
Dim rngOutput As Excel.Range
Dim iRowCount As Long Dim iColCount As Long
iRowCount = UBound(InputArray, 1) - LBound(InputArray, 1) iColCount = UBound(InputArray, 2) - LBound(InputArray, 2)
With rngTarget.Worksheet
Set rngOutput = .Range(rngTarget.Cells(1, 1), _ rngTarget.Cells(iRowCount + 1, iColCount + 1))
Application.EnableEvents = False
rngOutput.Value2 = InputArray
Application.EnableEvents = True
Set rngTarget = rngOutput ' resizes the range This is useful, most of the time
End With ' rngTarget.Worksheet
End Sub
注意事项:在旧版本的 Excel(Office 2000,如果我记得的话)中,数组 'write' 仍然 t运行 为 255 个字符。这不再是问题;如果您仍在使用 XL2000,包含超过 255 个字符的字符串的单元格就已经是一个问题,您可能会对 t运行cation.
感到高兴