【问题标题】:Extracting XML in VBA from Oracle DB从 Oracle DB 中提取 VBA 中的 XML
【发布时间】:2021-06-03 22:24:48
【问题描述】:

我有一个 Oracle DB,其中包含一个名为 CONTENT 的 XML 列:

<?xml version="1.0"?>
<PAGE>
  <INFO>
    <ID>324374</ID>
    <PAGE>ANE_CSC</PAGE>
  </INFO>
  <CAMPS>
    <CAMP KEY_CAMP="ACCESS_CONTROL">456675</CAMP>
    <CAMP KEY_CAMP="IDEN_ANAG">1458</CAMP>...
  </CAMPS>
</PAGE>

我正在尝试在 Excel 单元格中提取 IDEN_ANAG 值(因此:1458),但是我不知道如何在 VBA 中正确地阐述 XML 数据。

我尝试了一些方法(如getStringVal(), getClob(), EXTRACT() 之类的命令),但无法找到可行的解决方案。

这是我目前正在尝试做的:

Cmd.CommandText = "select XMLTYPE('<CAMP>'||CONTENT||'</CAMP>').getStringVal() from table WHERE ID = 324374
Set rs = Cmd.Execute()

Do While Not rs.EOF
    WSP1.Cells(CellWrite, 1).Value = rs.Fields(0).Value
    
    CellWrite = CellWrite + 1
    rs.MoveNext
Loop

我知道上面的代码实际上并没有提取特定的 ID,但我非常绝望,至少要从提取整个 XML 开始,然后尝试为其中的特定部分找到解决方案。

虽然我几乎可以肯定我只是在代码中犯了一个错误,但我已经根据互联网搜索、使用不同的功能等尝试了几种不同的结果,但我总是遇到像 Runtime error 或上面的代码给了我Runtime error: Character string buffer too small的错误。

如有任何关于如何提取特定数据的建议,我们将不胜感激。

【问题讨论】:

    标签: sql vba database oracle


    【解决方案1】:

    使用适当的 XML 解析器。您可以使用查询:

    SELECT iden_anag
    FROM   table_name t
           CROSS APPLY XMLTABLE(
             '/PAGE/CAMPS'
             PASSING XMLTYPE( t.content )
             COLUMNS
               iden_anag NUMBER PATH './CAMP[@KEY_CAMP="IDEN_ANAG"]'
           )
    WHERE  id = 324374
    

    SELECT XMLQUERY(
             '/PAGE/CAMPS/CAMP[@KEY_CAMP="IDEN_ANAG"]/text()'
             PASSING XMLTYPE( content )
             RETURNING CONTENT
           ) AS iden_anag
    FROM   table_name
    WHERE  id = 324374
    

    其中,对于您的示例数据:

    CREATE TABLE table_name ( id NUMBER, content CLOB );
    
    INSERT INTO table_name ( id, content ) VALUES (
      324374,
    '<?xml version="1.0"?>
    <PAGE>
      <INFO>
        <ID>324374</ID>
        <PAGE>ANE_CSC</PAGE>
      </INFO>
      <CAMPS>
        <CAMP KEY_CAMP="ACCESS_CONTROL">456675</CAMP>
        <CAMP KEY_CAMP="IDEN_ANAG">1458</CAMP>...
      </CAMPS>
    </PAGE>'
    );
    

    两个输出:

    | IDEN_ANAG | | --------: | |第1458章

    db小提琴here

    【讨论】:

    • 首先感谢您的帮助。然而,某处似乎有一堵墙。我试图将这两种变体都应用到完整的代码中,但我都遇到了问题。第一个带有CROSS APPLY 的变体给了我错误ORA-00905: Missing keyword,请记住这可能是因为我在SQL 字符串中并且@KEY_CAMP在引号内使用引号。 (我试图用=""IDEN_ANAG"" 逃脱,但它不起作用。第二个变体给了我:Type "xquery external variable" unknown。SQL 本身需要更改后的提取方法是否可能?
    • @Tree CROSS APPLY 适用于 Oracle 12c。如果您使用的是旧版本的 Oracle,请改用 CROSS JOINdb<>fiddle
    • 您好,我已尝试修改您提供的变体 2,方法是将 PASSING XMLTYPE(CONTENT) 删除为简单的 PASSING CONTENT(我的数据库中的 nb CONTENT 名称不同)并在最后添加 .getStringVal()最终返回了我在 excel 单元格中需要的值!非常感谢!
    • @Tree 如果您向我们提供表和示例数据的 DDL (CREATE TABLE) 和 DML (INSERT) 语句(而不仅仅是简单的英语描述和数据的文本表示,这可能会被误解)然后我们可能能够提供更好的解决方案,因为删除 XMLTYPE 会根据我在示例中使用的数据产生问题,但它可以解决您的问题这表明我们都使用了不同的方式来存储数据。清除设置环境的所有问题可以使获得答案变得更加简单。
    【解决方案2】:

    这是一个 Oracle 错误,当您尝试将一些大字符串放入 VARCHAR 数据类型时出现。

    您可以查看this documentation article,“使用 XMLType 方法选择 XML 数据”部分:

    您可以使用 PL/SQL、C 或 Java 选择 XMLType 数据。您还可以使用 XMLType 方法 getClobVal()getStringVal()getNumberVal()getBlobVal(csid) 分别以 CLOBVARCHARNUMBERBLOB 值检索 XML 数据。

    看来您的数据太大而无法放入getStringVal() 返回的VARCHAR,您需要使用getClobVal()

    另外,没有必要通过连接来创建 XML 数据,因为它无法处理所有的序列化细节(如 XML 中使用的符号应该被转换),并且您也可能面临VARCHAR 连接长度的相同限制。为此,您需要 XMLElement 函数:

    select
      xmlelement("Current_date", sysdate) as date_xml,
      xmlelement("SpecialSymbols", 'Symbols > and < need conversion') as spec_symbols_xml
    from dual
    
    DATE_XML | SPEC_SYMBOLS_XML :---------------------------------------- | :------------------------------------------------ -------------------- 2021-03-05 | 符号 >和 <需要转换

    db小提琴here

    您可以检查一堆XML manipulation functions 来构建XML,所以使用它们而不是字符串操作。 例如,以 XML 格式获取查询结果:

    select
      dbms_xmlgen.getxml('select object_name, object_type from all_objects where rownum < 3') as result_clob
    from dual
    
    |结果_CLOB | | :------------------------------------------------ -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------------------------------------------------ | |


    ORA$BASE
    EDITION

    /ROW>

    DUAL
    TABLE


    |

    db小提琴here

    但最好在数据库中执行所有 MXL 操作并将纯结果检索到 VBA。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-06
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2014-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多