【问题标题】:SQL Query output in VBA is different than in SQL OracleVBA 中的 SQL 查询输出与 SQL Oracle 中的不同
【发布时间】:2016-01-19 04:38:04
【问题描述】:

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 脚本中的 300 行 SQL 代码。
  • 是的...没有原始 SQL 和 VBA 中的实际 SQL 代码,我们无能为力。因为它是你的 SQL,所以 100% 没有意义,它最有可能是这个问题的罪魁祸首。
  • 为什么需要看?我的意思是什么会导致问题?在查询中使用带有简单命令的连接:distinct、case、instr、coalesce、nvl、listagg、exists..
  • 我的 SQL 是有道理的,否则它在 Oracle 中不起作用
  • 另外,您显示的声称的查询输出不可能来自任何一个查询。

标签: sql oracle vba excel recordset


【解决方案1】:

问题是CopyFromRecordset - 它被截断为 255 个字符,而且它不是唯一的 Excel.Range 方法。

问题是:我有没有没有的方法?在您进入写入范围之前,您是否有一个 OLEDB 驱动程序正在对您的 Recordset 执行此操作?

您应该在 VBA 中遍历您的记录集,并检查 VBA 中的违规字段是否有长度超过 255 个字符的值。如果字段已被截断,请尝试在连接字符串中使用本机 Oracle 客户端驱动程序,而不是 Microsoft Oracle OLEDB 提供程序 - Connections.com 将获得信息。

一旦您知道记录集实际上包含您的数据且没有截断,请再次尝试 CopyFromRecordset。我实际上并不期望它会写一个长度超过 255 个字符的字段,但是我已经有一段时间没有遇到错误了,它可能已经修复了,给悲观主义者一个惊喜总是很好。

接下来:

VBA 替代 CopyFromRecordset

这里有三个任务:

  1. 使用数据填充 VBA 数组变体 Recordset.GetRows();
  2. 转置数组,因为 GetRows 是错误的“四舍五入”方式 Excel;
  3. 调整目标范围并将数组写入为 Range.Value = Array,一个重复的任务 应该在 ArrayToRange() 例程中自动化。

...也许还有一些辅助工作来编写字段名称,但我在简短的回答中忽略了这一点。

最终结果是你运行这段代码:


    ArrayToRange rngTarget, ArrayTranspose(rst.GetRows)

转置数组是微不足道的,但无论如何:


Public Function ArrayTranspose(InputArray As Variant) As Variant
Application.Volatile False
Dim arrOutput As Variant
Dim i As Long Dim j As Long Dim iMin As Long Dim iMax As Long Dim jMin As Long Dim jMax As Long
iMin = LBound(InputArray, 1) iMax = UBound(InputArray, 1) jMin = LBound(InputArray, 2) jMax = UBound(InputArray, 2)
ReDim arrOutput(jMin To jMax, iMin To iMax)
For i = iMin To iMax For j = jMin To jMax arrOutput(j, i) = InputArray(i, j) Next j Next i
ArrayTranspose = arrOutput
End Function
...如果您不添加对数组维度的检查并在目标单元格中​​保留公式,那么 ArrayToRange 是微不足道的:关键是,如果范围的维度与数组的维度:

Public Sub ArrayToRange(rngTarget As Excel.Range, InputArray As Variant) ' 将数组写入 Excel 范围内的单个“命中”工作表 ' InputArray 应该是 Variant(Rows, Columns)
形式的二维结构 ' 目标范围自动调整为数组的尺寸,使用 ' 左上角单元格用作起点。
' 此子例程为常见的 VBA 和 Excel 任务保存重复编码。
' 作者:奈杰尔·赫弗南 http://Excellerando.blogspot.com

出错时继续下一步
将 rngOutput 调暗为 Excel.Range
将 iRowCount 变暗 将 iColCount 变暗
iRowCount = UBound(InputArray, 1) - LBound(InputArray, 1) iColCount = UBound(InputArray, 2) - LBound(InputArray, 2)
使用 rngTarget.Worksheet
设置 rngOutput = .Range(rngTarget.Cells(1, 1), _ rngTarget.Cells(iRowCount + 1, iColCount + 1))
Application.EnableEvents = False

rngOutput.Value2 = 输入数组
Application.EnableEvents = True
Set rngTarget = rngOutput ' 调整范围大小 这很有用,大多数时间
以 'rngTarget.Worksheet 结尾
结束子

注意事项:在旧版本的 Excel(Office 2000,如果我记得的话)中,数组“写入”仍被截断为 255 个字符。这不再是问题;如果您仍在使用 XL2000,那么包含超过 255 个字符的字符串的单元格就足以解决您可能会对截断感到高兴的问题。

【讨论】:

  • 谢谢你成功了!!完美,只需要创建一个转置数组并将其粘贴到 excel 表中。再次感谢您!
  • @Nigel Heffernan 我尝试了你提供的解决方案。但这对我没有用。我的问题似乎有点不同。当我分别从 VBA 和 Oracle 运行相同的查询时,我的 RECORDSET 值是不同的。
【解决方案2】:

问题在于这两个查询完全相同。

您的 VBA 版本中有以下内容,但您的 Oracle 版本中没有:

WHERE inh.invoice_date >= to_date('" & dat1 & "','YYYY.MM.DD') 
AND inh.invoice_date <= to_date('" & dat2 & "','YYYY.MM.DD' ) ) XX   

可能还有其他差异,但我立刻就想到了。

【讨论】:

  • 所以??有一个日期过滤器是一个额外的字段。如果我将相同的行合并到 SQL 代码中并通过 Orace 启动: WHERE inh.invoice_date >= to_date('2015.10.15','YYYY.MM.DD') 和 inh.invoice_date
  • 您显然没有抓住重点...您向数据库提出了不同的问题,并且很困惑为什么会得到不同的答案。我没有时间查看您的其余查询,但可能这不是唯一的区别。
  • 我以 1:1 的比例准确地进行了相同的查询,但仍然出现此错误。如果您不熟悉该问题,请不要向此主题发送垃圾邮件
  • @Siyual - 除了空格和大小写,这似乎是唯一的区别,有点令人惊讶。
  • @orangutangas 垃圾邮件?你问了一个问题,我回答了。我几乎不认为这是垃圾邮件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-07
  • 2013-06-20
  • 2020-08-14
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多