Oracle 12c:WITH子句中的函数不适用于ADODB

时间:2016-08-23 13:36:45

标签: oracle vba ms-access adodb oracle12c

select banner
from v$version
;


BANNER
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
"CORE   12.1.0.2.0  Production"
TNS for Solaris: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production

通过其12c版本,Oracle增加了允许直接在SQL语句顶部声明Pl / SQL函数的功能(参见https://oracle-base.com/articles/12c/with-clause-enhancements-12cr1

这可能是一个非常方便的功能,尤其是在需要从用户权限限制为SELECT语句的数据库中提取数据的项目上。

以下(显然简化的)查询在Oracle SQL Developer中运行良好:

with 
  function add_string(p_string in varchar2) return varchar2
  is
    --Function to add a string
    l_buffer varchar2(32767);
  begin
    l_buffer := p_string || ' works!';
    --
    return l_buffer;
    --
  end ; 
--
select add_string('Yes, it') as outVal
from dual
;

---------
OUTVAL
Yes, it works!

现在,我正在尝试将基于相同原理的查询结果集加载到MS-Access 2007中的ADODB Recordset中。我知道ADO不会无缝地处理以WITH子句开头的查询(例如,请参阅Why can't I do a "with x as (...)" with ADODB and Oracle?)。我通常解决这个问题的方法是将查询括在SELECT块中,如下所示:

select hey_yo 
from (
  with sub as (
    select 'hey' as hey
    from dual
  )
  select hey || ' yo!' as hey_yo
  from sub
)
;

---------
HEY_YO
hey yo!

不幸的是,在处理WITH子句中的函数时,这似乎不是Oracle中的合法语法:

select *
from (
  with 
    function add_string(p_string in varchar2) return varchar2
    is
      --Function to add a string
      l_buffer varchar2(32767);
    begin
      l_buffer := p_string || ' works!';
      --
      return l_buffer;
      --
    end ; 
  --
  select add_string('Yes, it') as outVal
  from dual
)
;

---------
PLS-00103: Encountered the symbol ")" when expecting one of the following:

   . , @ ; for <an identifier>
   <a double-quoted delimited-identifier> group having intersect
   minus order partition start subpartition union where connect
   sample
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.

这是我尝试在VBA中运行的子项:

Sub TestSub()

    Dim conn As ADODB.Connection
    Dim rs As ADODB.Recordset

    'Connection details
    Dim strHostName As String
    Dim nPortNum As Integer
    Dim strUser As String
    Dim strPassword As String
    Dim strServiceName As String


    Dim strConnection As String
    Dim strSQL As String

    Set conn = New ADODB.Connection

    '[... set credentials ...]

    'Open Connection
    With conn
        .ConnectionString = "Provider=MSDAORA;" & _
        "Data Source=(DESCRIPTION=(ADDRESS_LIST=" & _
        "(ADDRESS=(PROTOCOL=TCP)(HOST=" & strHostName & ")(PORT=" & nPortNum & ")))(CONNECT_DATA=(SERVICE_NAME=" & strServiceName & ")));" & _
        "User ID=" & strUser & ";Password=" & strPassword & ";"

        .Open

    End With

    Set rs = New ADODB.Recordset

    strSQL = "WITH FUNCTION add_string(p_string IN VARCHAR2) RETURN VARCHAR2 IS l_buffer VARCHAR2(32767); BEGIN l_buffer := p_string || ' works!'; RETURN l_buffer; END ; SELECT add_string('Yes, it') AS outval FROM dual"
    rs.Open strSQL, conn, adOpenStatic, adLockReadOnly

    '[... do stuff with data ...]
    rs.MoveFirst
    Debug.Print rs.Fields(0).Value

    rs.Close
    Set rs = Nothing

    conn.Close
    Set conn = Nothing

End Sub

任何想法如何解决这个问题? (不幸的是,在DB中编译函数不是这个特定项目的选项。)

更新 我应该提一下运行VBA代码时得到的错误:

  

运行时错误3704:对象为时不允许操作   闭合。

rs.MoveFirst

2 个答案:

答案 0 :(得分:3)

使用&#34; Oracle Provider for OLE DB&#34;而不是&#34; Microsoft OLE DB Provider for Oracle&#34;。可以从此处下载Oracle提供程序:32-bit Oracle Data Access Components (ODAC) and NuGet Downloads

Microsoft提供商已经deprecated多年,它没有进一步开发,不应该再使用了。当前版本的Oracle提供程序是12.1,即它还应该支持新的Oracle 12c功能。

连接字符串为Provider=OraOLEDB.Oracle; ...而不是Provider=MSDAORA;...

答案 1 :(得分:0)

不幸的是,我无法测试以下内容,因为我在这里只有一台Oracle 11。

理论上它应该有效。但是你应该使用ADODB.Command直接发送SQL,直接发送到Oracle

试试这个:

Dim strConnection As String
Dim strSQL As String

Dim cmdQuery As ADODB.Command


Set conn = New ADODB.Connection

'[... set credentials ...]

'Open Connection
With conn
    .ConnectionString = "Provider=MSDAORA;" & _
    "Data Source=(DESCRIPTION=(ADDRESS_LIST=" & _
    "(ADDRESS=(PROTOCOL=TCP)(HOST=" & strHostName & ")(PORT=" & nPortNum & ")))(CONNECT_DATA=(SERVICE_NAME=" & strServiceName & ")));" & _
    "User ID=" & strUser & ";Password=" & strPassword & ";"

    .Open

End With

Set rs = New ADODB.Recordset

    strSQL = "WITH FUNCTION add_string(p_string IN VARCHAR2) RETURN VARCHAR2 IS l_buffer VARCHAR2(32767); BEGIN l_buffer := p_string || ' works!'; RETURN l_buffer; END ; SELECT add_string('Yes, it') AS outval FROM dual"

Set cmdQuery = New ADODB.Command
cmdQuery.ActiveConnection = conn
cmdQuery.CommandText = strSQL


With rs
    .LockType = adLockPessimistic
    .CursorType = adUseClient
    .CursorLocation = adUseClient
    .Open cmdQuery
End With    

'[... do stuff with data ...]