【问题标题】:Oracle 12c: Functions in the WITH Clause do not work with ADODBOracle 12c: WITH 子句中的函数不适用于 ADODB
【发布时间】:2016-12-30 09:04:27
【问题描述】:
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 记录集中。我知道 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!

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

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

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

更新: 我应该提到我在运行 VBA 代码时遇到的错误:

运行时错误 3704:当对象处于运行状态时不允许操作 关闭。

rs.MoveFirst

【问题讨论】:

  • 您能否尝试使用 Oracle Provider for OLE DB:Provider=OraOLEDB.Oracle 而不是 MSDAORA。你可以从这里下载它:32-bit Oracle Data Access Components。它可能会起作用,Microsoft 提供商是 deprecated 很长时间了
  • @WernfriedDomscheit:恐怕我被 MS 驱动卡住了,客户端对软件下载/安装非常严格。
  • 也许你运气好,并且已经安装了 oledb 提供程序。
  • @WernfriedDomscheit:你是对的,它已安装,它解决了问题! :) 您可以发表您的评论作为答案,以便我接受吗?

标签: oracle vba ms-access adodb oracle12c


【解决方案1】:

很遗憾,我无法测试以下内容,因为我这里只有一个 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 ...]

【讨论】:

  • 感谢您的回答!不幸的是,我得到了同样的错误。
【解决方案2】:

使用“Oracle Provider for OLE DB”而不是“Microsoft OLE DB Provider for Oracle”。 Oracle 提供程序可以从这里下载:32-bit Oracle Data Access Components (ODAC) and NuGet Downloads

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

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

【讨论】:

  • 谢谢,这让我很开心!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
相关资源
最近更新 更多