如何解决Excel崩溃某些SELECT语句?

时间:2013-08-14 11:40:00

标签: sql vba oracle excel-vba ado

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

  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
    
  3. 这是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
    

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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. 您可以切换到Oracle的软件吗?如果我使用Provider=ORAOLEDB.ORACLE,您的第一个子程序将适用于我。如果我使用Oracle DSN,您的第二个子例程也可以工作。我无法在我的计算机上连接MSDAORA{Microsoft ODBC for Oracle}。 (虽然这可能是我的错。)
  2. 尝试将model return updated rows更改为model keep nav return updated rows main main_model。这是一个语义无意义的变化,它只是 明确列出默认值。但也许这足以避免你遇到的解析错误。