【问题标题】:Oracle, XML to insert statementOracle, XML 插入语句
【发布时间】:2019-04-21 21:23:49
【问题描述】:

我有示例 xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <tns:getAbcResponse xmlns:tns="http://xyz.abc.com">
            <abc-name>CONTRACT_STATUS</abc-name>
            <abc-values>
                <attribute>
                    <name>7</name>
                    <value-list>
                        <value>
                            <name>CONTRACT_STATUS</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>CONTRACT_STATUS_DESC</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>SOURCE_SYSTEM</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>SOURCE_VALUE</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>SOURCE_DESC</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>VISIBLE</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>REQUIRED</name>
                            <value>xyzabc</value>
                        </value>
                    </value-list>
                </attribute>
                <attribute>
                    <name>7</name>
                    <value-list>
                        <value>
                            <name>CONTRACT_STATUS</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>CONTRACT_STATUS_DESC</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>SOURCE_SYSTEM</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>SOURCE_VALUE</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>SOURCE_DESC</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>VISIBLE</name>
                            <value>xyzabc</value>
                        </value>
                        <value>
                            <name>REQUIRED</name>
                            <value>xyzabc</value>
                        </value>
                    </value-list>
                </attribute>
            </abc-values>
            <status error-code="0">
                <error-msg>OK</error-msg>
            </status>
        </tns:getAbcResponse>
    </soapenv:Body>
</soapenv:Envelope>

在此示例中,一个&lt;attribute&gt; 标记为 1 行,我需要将其插入到表中。

我设法构建了一个查询:

  with response(xm) as ( select xmltype('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><tns:getAbcResponse xmlns:tns="http://xyz.abc.com"><abc-name>CONTRACT_STATUS</abc-name><abc-values>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>xyzabc</value></value><value><name>SOURCE_VALUE</name><value>xyzabc</value></value><value><name>SOURCE_DESC</name><value>xyzabc</value></value><value><name>VISIBLE</name><value>xyzabc</value></value><value><name>REQUIRED</name><value>xyzabc</value></value></value-list></attribute>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>xyzabc</value></value><value><name>SOURCE_VALUE</name><value>xyzabc</value></value><value><name>SOURCE_DESC</name><value>xyzabc</value></value><value><name>VISIBLE</name><value>xyzabc</value></value><value><name>REQUIRED</name><value>xyzabc</value></value></value-list></attribute>
</abc-values><status error-code="0"><error-msg>OK</error-msg></status></tns:getAbcResponse></soapenv:Body></soapenv:Envelope>')from dual)
SELECT  n.att_name  AS name,
        v.name      AS att_name,
        v.value     AS att_value
FROM    response r,
        XMLTABLE
        (
          '//abc-values/attribute'
          PASSING r.xm
          COLUMNS
            att_name VARCHAR2(30) PATH 'name',
            value_list XMLTYPE PATH 'value-list'
        ) n,
        XMLTABLE 
        ( 
          'value-list/value'
          PASSING n.value_list
          COLUMNS
            name   varchar2(30) PATH 'name',
            value  varchar2(30) PATH 'value'
        ) v;

采用这种方法,我需要:

  1. 从此查询中获取前 7 行,
  2. 转化为单个插入查询->执行/放入集合
  3. 从此查询中获取接下来的 7 行

换一种方式:

注意:name 列是某种 id,对表 v 中的每一行重复。

我完全不知道如何实现这一点。 任何想法,不同的方法都将受到欢迎。

谢谢:)

【问题讨论】:

  • 前 7 行与后 7 行的区别是什么?我的意思是,您的样本数据对于所有内容都是相同的(例如,两组在相同的位置具有相同的值)。总是 7 行吗?
  • 我只是混淆了数据。
  • 它有助于提供准确反映您要处理的要求的示例数据!
  • 在这种情况下它真的没有。我正在尝试对列名(如contract_status、source_system)进行操作,因此机制应该不会给出关于数据的cr...。如果 xml 包含 'xyz' - 程序将插入 'xyz'。如果'abc'则'abc'。如果对您有帮助,您可以在每个“xyzabc”的末尾添加一个不同的数字。
  • 确实如此。如果所有数据都相同,您怎么知道您在正确的位置获取正确的值?事实上,我在示例数据中添加了数字,以便在我的回答中清晰,因此您可以确定这些值按预期返回。那确实应该由您完成,因为您是寻求帮助的人。请确保您在下次提出问题时提供有用的示例数据,以免浪费大家的时间。

标签: xml oracle web-services plsql


【解决方案1】:

如果您拥有独特的数据,您可能会改变您现在拥有的数据。但您也可以独立提取每一列作为第二个 XMLTable 的一部分:

with ...
SELECT  n.att_name  AS name,
        v.*
FROM    response r,
        XMLTABLE
        (
          '//abc-values/attribute'
          PASSING r.xm
          COLUMNS
            att_name VARCHAR2(30) PATH 'name',
            value_list XMLTYPE PATH 'value-list'
        ) n,
        XMLTABLE 
        ( 
          'value-list'
          PASSING n.value_list
          COLUMNS
            contract_status varchar2(30)
              PATH 'value/name[text()="CONTRACT_STATUS"]/../value',
            contract_status_desc varchar2(30)
              PATH 'value/name[text()="CONTRACT_STATUS_DESC"]/../value',
            source_system varchar2(30)
              PATH 'value/name[text()="SOURCE_SYSTEM"]/../value',
            source_value varchar2(30)
              PATH 'value/name[text()="SOURCE_VALUE"]/../value',
            source_desc varchar2(30)
              PATH 'value/name[text()="SOURCE_DESC"]/../value',
            visible varchar2(30)
              PATH 'value/name[text()="VISIBLE"]/../value',
            required varchar2(30)
              PATH 'value/name[text()="REQUIRED"]/../value'
        ) v;

NAME                           CONTRACT_STATUS                CONTRACT_STATUS_DESC           SOURCE_SYSTEM                  SOURCE_VALUE                   SOURCE_DESC                    VISIBLE                        REQUIRED                      
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------
7                              xyzabc                         xyzabc                         xyzabc                         xyzabc                         xyzabc                         xyzabc                         xyzabc                        
7                              xyzabc                         xyzabc                         xyzabc                         xyzabc                         xyzabc                         xyzabc                         xyzabc                        

或者使用单个 XMLTable,假设每个节点有一个值列表:

SELECT  x.*
FROM    response r,
        XMLTABLE
        (
          '//abc-values/attribute'
          PASSING r.xm
          COLUMNS
            name VARCHAR2(30) PATH 'name',
            contract_status varchar2(30)
              PATH 'value-list/value/name[text()="CONTRACT_STATUS"]/../value',
            contract_status_desc varchar2(30)
              PATH 'value-list/value/name[text()="CONTRACT_STATUS_DESC"]/../value',
            source_system varchar2(30)
              PATH 'value-list/value/name[text()="SOURCE_SYSTEM"]/../value',
            source_value varchar2(30)
              PATH 'value-list/value/name[text()="SOURCE_VALUE"]/../value',
            source_desc varchar2(30)
              PATH 'value-list/value/name[text()="SOURCE_DESC"]/../value',
            visible varchar2(30)
              PATH 'value-list/value/name[text()="VISIBLE"]/../value',
            required varchar2(30)
              PATH 'value-list/value/name[text()="REQUIRED"]/../value'
        ) x;

要将其转换为插入,请使用 with 子句从子查询中选择 *,或者将 XML 值嵌入到 XMLTable 中:

INSERT INTO some_table (name, contract_status, contract_status_desc,
  source_system, source_value, source_desc, visble, required)
SELECT  *
FROM    XMLTABLE
        (
          '//abc-values/attribute'
          PASSING xmltype('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><tns:getAbcResponse xmlns:tns="http://xyz.abc.com"><abc-name>CONTRACT_STATUS</abc-name><abc-values>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>xyzabc</value></value><value><name>SOURCE_VALUE</name><value>xyzabc</value></value><value><name>SOURCE_DESC</name><value>xyzabc</value></value><value><name>VISIBLE</name><value>xyzabc</value></value><value><name>REQUIRED</name><value>xyzabc</value></value></value-list></attribute>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>xyzabc</value></value><value><name>SOURCE_VALUE</name><value>xyzabc</value></value><value><name>SOURCE_DESC</name><value>xyzabc</value></value><value><name>VISIBLE</name><value>xyzabc</value></value><value><name>REQUIRED</name><value>xyzabc</value></value></value-list></attribute>
</abc-values><status error-code="0"><error-msg>OK</error-msg></status></tns:getAbcResponse></soapenv:Body></soapenv:Envelope>')
          COLUMNS
            name VARCHAR2(30) PATH 'name',
            contract_status varchar2(30)
              PATH 'value-list/value/name[text()="CONTRACT_STATUS"]/../value',
            contract_status_desc varchar2(30)
              PATH 'value-list/value/name[text()="CONTRACT_STATUS_DESC"]/../value',
            source_system varchar2(30)
              PATH 'value-list/value/name[text()="SOURCE_SYSTEM"]/../value',
            source_value varchar2(30)
              PATH 'value-list/value/name[text()="SOURCE_VALUE"]/../value',
            source_desc varchar2(30)
              PATH 'value-list/value/name[text()="SOURCE_DESC"]/../value',
            visible varchar2(30)
              PATH 'value-list/value/name[text()="VISIBLE"]/../value',
            required varchar2(30)
              PATH 'value-list/value/name[text()="REQUIRED"]/../value'
        );

...当然,或者你真正从哪里得到它。

路径查找具有特定文本值的value/name 节点,然后为每个特定名称查找相邻的value。 (@Boneist 的语法实际上是相同的原理,但更短更清晰;不知道为什么我写了这么长!所以你可以在上面的第一个版本中使用value[name="CONTRACT_STATUS"]/value,在第二个版本中使用单个 XMLTable 的value-list/value[name="CONTRACT_STATUS"]/value。我将保留我的原样以显示差异...)

还请注意,这种方法允许您为每个提取的列值声明合适的数据类型和大小,而不必为所有列值使用varchar2(30)。 (例如,我想像必需的、可见的和单字符标志)。

【讨论】:

  • 我不得不用谷歌搜索我使用的语法......我最终从my own question 那里抄袭了这个主题!好尴尬……哈哈!
  • 我想我走了很长一段路,因为我通常对属性进行那种过滤,当我意识到我不能在这里使用 @ 时,我想得还不够。但是我已经忘记了我搜索我正在尝试做 IRL 的事情的次数,并且在意识到我写它之前已经完成了一半的答案。这更令人担忧...
【解决方案2】:

这是选择数据的一种方式:

with response(xm) as ( select xmltype('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><tns:getAbcResponse xmlns:tns="http://xyz.abc.com"><abc-name>CONTRACT_STATUS</abc-name><abc-values>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>11xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>12xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>13xyzabc</value></value><value><name>SOURCE_VALUE</name><value>14xyzabc</value></value><value><name>SOURCE_DESC</name><value>15xyzabc</value></value><value><name>VISIBLE</name><value>16xyzabc</value></value><value><name>REQUIRED</name><value>17xyzabc</value></value></value-list></attribute>
<attribute><name>7</name><value-list><value><name>CONTRACT_STATUS</name><value>21xyzabc</value></value><value><name>CONTRACT_STATUS_DESC</name><value>22xyzabc</value></value><value><name>SOURCE_SYSTEM</name><value>23xyzabc</value></value><value><name>SOURCE_VALUE</name><value>24xyzabc</value></value><value><name>SOURCE_DESC</name><value>25xyzabc</value></value><value><name>VISIBLE</name><value>26xyzabc</value></value><value><name>REQUIRED</name><value>27xyzabc</value></value></value-list></attribute>
</abc-values><status error-code="0"><error-msg>OK</error-msg></status></tns:getAbcResponse></soapenv:Body></soapenv:Envelope>') from dual)
SELECT  n.att_name  AS name,
        v.contract_status,
        v.contract_status_desc,
        v.source_system,
        v.source_value,
        v.source_desc,
        v.visible,
        v.required
FROM    response r,
        XMLTABLE
        (
          '//abc-values/attribute'
          PASSING r.xm
          COLUMNS
            att_name VARCHAR2(30) PATH 'name',
            value_list XMLTYPE PATH 'value-list'
        ) n,
        XMLTABLE 
        ( 
          'value-list'
          PASSING n.value_list
          COLUMNS
            contract_status varchar2(30) PATH 'value[name="CONTRACT_STATUS"]/value',
            contract_status_desc varchar2(30) PATH 'value[name="CONTRACT_STATUS_DESC"]/value',
            source_system varchar2(30) PATH 'value[name="SOURCE_SYSTEM"]/value',
            source_value varchar2(30) PATH 'value[name="SOURCE_VALUE"]/value',
            source_desc varchar2(30) PATH 'value[name="SOURCE_DESC"]/value',
            visible varchar2(30) PATH 'value[name="VISIBLE"]/value',
            required varchar2(30) PATH 'value[name="REQUIRED"]/value'
        ) v;

给出:

NAME                           CONTRACT_STATUS                CONTRACT_STATUS_DESC           SOURCE_SYSTEM                  SOURCE_VALUE                   SOURCE_DESC                    VISIBLE                        REQUIRED
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------
7                              11xyzabc                       12xyzabc                       13xyzabc                       14xyzabc                       15xyzabc                       16xyzabc                       17xyzabc
7                              21xyzabc                       22xyzabc                       23xyzabc                       24xyzabc                       25xyzabc                       26xyzabc                       27xyzabc

然后您可以简单地在 insert into ... (...) select ... 语句中使用它。

如果在 PL/SQL 中使用它,您可以简单地在初始 XMLTABLE 中引用 xmltype 变量,而不必使用 response 子查询,但我希望您已经知道这一点。

【讨论】:

  • FWIW,我认为亚历克斯的答案应该是正确的;他演示了如何只使用单个 XMLTABLE 来获得结果——唯一的区别是路径;我用过的比 Alex 用过的更紧凑。如果我是你,我会切换到他的答案,使用单个 XMLTABLE 解决方案,但可能会将路径更改为我使用的样式。不过,我猜是 YMMV。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多