6

这两个语句相似,但第二个语句会导致 Excel 在每次执行时崩溃。唯一的区别是modelmodel return updated rows(我专门设计了这个最小的例子,以便查询在任何一种情况下都返回完全相同的数据,我的实际 SQL 当然是不同的):

  1. select *
    from( select *
          from ( select 1 id, 100 val from dual
                 union all 
                 select 2 id, 200 val from dual )
          model
          dimension by (id)
          measures (val)
          rules ( val[1] = val[cv()]+1 ) )
    where val=101
    
  2. select *
    from( select *
          from ( select 1 id, 100 val from dual
                 union all 
                 select 2 id, 200 val from dual )
          model return updated rows
          dimension by (id)
          measures (val)
          rules ( val[1] = val[cv()]+1 ) )
    where val=101
    

这是 ADO 中错误的一个孤立示例,还是存在使解析器崩溃的已知 SQL 语句类(我什至不确定为什么 ADO 会解析语句而不是将其传递给数据库)。

这是崩溃版本的完整 VBA 代码:

Option Explicit
Sub Go()

    Dim lConn As ADODB.Connection
    Dim lRecordset As ADODB.Recordset
    'Dim lRecordset
    Dim sSQL As String

    Set lConn = New ADODB.Connection
    Set lRecordset = New ADODB.Recordset
    'Set lRecordset = CreateObject("ADODB.Recordset")

    lConn.Open "Provider=MSDAORA;Data Source=(DESCRIPTION=(CID=GTU_APP)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=devdb)(PORT=1521)))(CONNECT_DATA=(SID=oracle)(SERVER=DEDICATED)));User Id=csuk;Password=thisisnotmyrealpassword;"

    With lRecordset
        sSQL = "select * " & _
               "from( select * " & _
               "      from ( select 1 id, 100 val from dual " & _
               "             Union all " & _
               "             select 2 id, 200 val from dual ) " & _
               "      model return updated rows " & _
               "      dimension by(id) " & _
               "      measures (val) " & _
               "      rules ( val[1] = val[cv()]+1 ) ) " & _
               "where val=101"
        .Open sSQL, lConn
        While Not .EOF
            Sheets(1).Cells(1, 1) = ![Val]
            .MoveNext
        Wend
        .Close
    End With

    Set lRecordset = Nothing
    lConn.Close
    Set lConn = Nothing

End Sub

作为对评论的回应,我使用 DAO 尝试了相同的 SQL,令我困惑的是,我们得到了相同的结果。以下代码使 Excel 崩溃,但只需删除return updated rows它即可使其按预期工作:

Option Explicit
Sub Go()

    Dim lWorkspace As DAO.Workspace
    Dim lDatabase As DAO.Database
    Dim lRecordset As DAO.Recordset

    Dim sSQL As String

    sSQL = "select * " & _
           "from( select * " & _
           "      from ( select 1 id, 100 val from dual " & _
           "             Union all " & _
           "             select 2 id, 200 val from dual ) " & _
           "      model return updated rows " & _
           "      dimension by(id) " & _
           "      measures (val) " & _
           "      rules ( val[1] = val[cv()]+1 ) ) " & _
           "where val=101"

    Set lWorkspace = DBEngine.Workspaces(0)
    Set lDatabase = lWorkspace.OpenDatabase("", False, False, "Driver={Microsoft ODBC for Oracle};Server=devdb:1521/oracle;Uid=charts_csuk_uksoft;Pwd=thisisnotmyrealpassword;")
    Set lRecordset = lDatabase.OpenRecordset(sSQL, dbOpenDynaset, dbSQLPassThrough)

    With lRecordset
        While Not .EOF
            Sheets(1).Cells(1, 1) = ![Val]
            .MoveNext
        Wend
    End With

    Set lRecordset = Nothing
    Set lDatabase = Nothing
    Set lWorkspace = Nothing

End Sub
4

2 回答 2

2

这更像是一种解决方法,而不是解决方案,但它可能是隐藏任何 SQL 语句的选项,这会扰乱 ADO(或 Excel,就此而言),在VIEW. 对于动态语句(即在运行时更改视图),您可以考虑在其中使用过程EXECUTE IMMEDIATE CREATE OR REPLACE VIEW ...

于 2013-08-15T08:58:18.207 回答
1

您可以通过构建自定义版本的return updated rows.

添加一个假列来跟踪已更新的内容,并将其初始化为 false (0)。然后添加一个度量,并为每个规则创建一个类似的规则,将标志设置为 true (1)。最后,添加一个谓词以仅包含标志为 1 的行。

这显然不是一个理想的解决方案。它会更慢。而且您必须记住构建填充标志的所有额外规则。

select id, val
from( select *
      from ( select 1 id, 100 val, 0 is_updated_or_inserted from dual
             union all 
             select 2 id, 200 val, 0 is_updated_or_inserted from dual 
             union all 
             select 3 id, 101 val, 0 is_updated_or_inserted from dual )
      model
      dimension by (id)
      measures (val, is_updated_or_inserted)
      rules ( val[1] = val[cv()]+1 , is_updated_or_inserted[1] = 1) )
where val=101
  and is_updated_or_inserted = 1

更新

这里还有一些想法。

  1. 你能切换到甲骨文的软件吗?如果我使用你的第一个子程序对我有用Provider=ORAOLEDB.ORACLE。如果我使用 Oracle DSN,您的第二个子程序就可以工作。我无法在我的机器上获取MSDAORA或连接。{Microsoft ODBC for Oracle}(虽然这可能是我的错。)
  2. 尝试更改model return updated rowsmodel keep nav return updated rows main main_model. 这是一个语义上没有意义的更改,它只是明确列出了默认值。但也许这足以避免您遇到的解析错误。
于 2013-08-14T18:32:46.750 回答