-1

我是使用 Oracle 的 xml DB 的新手,我开始了解它,但有一件很重要的事情我无法做到:我需要确定 1. 元素是否存在 2. 如果它是空的

不幸的是 XMLExists() 只是混合了两个答案。

我查询的一小部分:

SELECT case when XMLEXISTS('/' passing by ref c3.CLASS) then 1 else 0 end E_CLASS,        
       c3.CLASS      
FROM XML_TEST x,
   XMLTABLE ('/Data/EMPLOYER'
                    PASSING x.File_XML
                    COLUMNS DOSSIER           NUMBER(8)       PATH     'DOSSIER',
                            SUMMARY           XMLTYPE         PATH 'SUMMARY'
            ) e,
   XMLTABLE ('/SUMMARY'
                PASSING e.SUMMARY
                COLUMNS BEGINDATE          DATE            PATH 'BEGINDATE',                            
                        WORKER             XMLTYPE         PATH 'WORKER'
            ) c1,
   XMLTABLE ('/WORKER'
                PASSING c1.WORKER
                COLUMNS NRWORKER           NUMBER(7)       PATH 'NRWORKER',                            
                        RESULT_DETAIL      XMLTYPE         PATH 'RESULT_DETAIL'
            ) c2 ,
    XMLTABLE ('/RESULT_DETAIL'
                PASSING c2.RESULT_DETAIL
                COLUMNS CODE               CHAR(5)         PATH 'CODE',                            
                        MINUTES            NUMBER(5)       PATH 'MINUTES',                            
                        CLASS              CHAR(1)         PATH 'CLASS'                            
            ) c3 ;
4

2 回答 2

0

XMLEXISTS确实为空元素返回 true,您只是发送它c3.CLASS,它是一个CHAR(1)列而不是一个XMLTYPE,因此它不会检测到根元素 ( /) 并返回 false。

这是您可以使用它的不同方式的示例。我将 CLASS 的 XMLTYPE 副本添加到 c3,并在 SELECT 子句中引用它。尝试从样本数据或整个 CLASS 节点中删除“z”,看看会发生什么。

有关如何编写 XPATH 查询以检查节点是否为空的信息,请参阅此类似问题。

-- sample data
with xml_test as (select xmltype('<Data><EMPLOYER><SUMMARY><WORKER><RESULT_DETAIL><CLASS>z</CLASS></RESULT_DETAIL></WORKER></SUMMARY></EMPLOYER></Data>') as file_xml from dual)
-- your query
SELECT --case when XMLEXISTS('/' passing by ref c3.class) then 1 else 0 end E_CLASS, /* won't work if CLASS is non-empty */
       case when XMLEXISTS('/' passing by ref c3.class_x) then 1 else 0 end E_CLASS_X,
       case when XMLEXISTS('/RESULT_DETAIL/CLASS' passing by ref c2.RESULT_DETAIL) then 1 else 0 end E_RD_CLASS,
       c3.CLASS, 
       c3.CLASS_X, 
       -- but this probably does what you want, detect if CLASS exists and is empty:
       case when XMLEXISTS('/CLASS' passing by ref c3.class_x)
             and not XMLEXISTS('/CLASS/text()' passing by ref c3.class_x) then 1 else 0 end EMPTY_CLASS
FROM XML_TEST x,
   XMLTABLE ('/Data/EMPLOYER'
                    PASSING x.File_XML
                    COLUMNS DOSSIER           NUMBER(8)       PATH     'DOSSIER',
                            SUMMARY           XMLTYPE         PATH 'SUMMARY'
            ) e,
   XMLTABLE ('/SUMMARY'
                PASSING e.SUMMARY
                COLUMNS BEGINDATE          DATE            PATH 'BEGINDATE',                            
                        WORKER             XMLTYPE         PATH 'WORKER'
            ) c1,
   XMLTABLE ('/WORKER'
                PASSING c1.WORKER
                COLUMNS NRWORKER           NUMBER(7)       PATH 'NRWORKER',                            
                        RESULT_DETAIL      XMLTYPE         PATH 'RESULT_DETAIL'
            ) c2 ,
    XMLTABLE ('/RESULT_DETAIL'
                PASSING c2.RESULT_DETAIL
                COLUMNS CODE               CHAR(5)         PATH 'CODE',                            
                        MINUTES            NUMBER(5)       PATH 'MINUTES',                            
                        CLASS              CHAR(1)         PATH 'CLASS',
                        CLASS_X            XMLTYPE         PATH 'CLASS'  -- added an XMLTYPE column with the same data                          
            ) c3 ;
于 2019-02-13T14:11:35.183 回答
0

您可以使用//[not(text())][not(*)]查找没有任何文本且没有子元素的元素。

因此,在您的上下文中,您可以使用:

CASE
WHEN c2.RESULT_DETAIL IS NULL
     OR
     XMLEXISTS(
       '/RESULT_DETAIL/CLASS[not(text())][not(*)]'
       PASSING c2.RESULT_DETAIL
     )
THEN 1
ELSE 0
END AS isClassEmpty

您也可以LEFT OUTER JOIN使用您的表格,以便仍然出现缺失的元素,然后您可以测试以查看值是否CLASSNULL

甲骨文设置

CREATE TABLE XML_TEST ( File_XML ) AS
SELECT XMLTYPE( '<Data>
  <EMPLOYER>
    <DOSSIER>1</DOSSIER>
    <SUMMARY>
      <BEGINDATE>2019-02-13</BEGINDATE>
      <WORKER>
        <NRWORKER>42</NRWORKER>
        <RESULT_DETAIL>
          <CODE>12345</CODE>
          <MINUTES>0</MINUTES>
          <CLASS></CLASS>
        </RESULT_DETAIL>
      </WORKER>
    </SUMMARY>
  </EMPLOYER>
</Data>' ) FROM DUAL UNION ALL
SELECT XMLTYPE( '<Data>
  <EMPLOYER>
    <DOSSIER>2</DOSSIER>
    <SUMMARY>
      <BEGINDATE>2019-02-14</BEGINDATE>
      <WORKER>
        <NRWORKER>1</NRWORKER>
        <RESULT_DETAIL>
          <CODE>98765</CODE>
          <MINUTES>600</MINUTES>
          <CLASS>B</CLASS>
        </RESULT_DETAIL>
      </WORKER>
    </SUMMARY>
  </EMPLOYER>
</Data>' ) FROM DUAL UNION ALL
SELECT XMLTYPE( '<Data>
  <EMPLOYER>
    <DOSSIER>3</DOSSIER>
    <SUMMARY>
      <BEGINDATE>2019-02-14</BEGINDATE>
      <WORKER>
        <NRWORKER>7</NRWORKER>
      </WORKER>
    </SUMMARY>
  </EMPLOYER>
</Data>' ) FROM DUAL

查询

SELECT Dossier,
       BeginDate,
       NRWorker,
       Code,
       Minutes,
       Class,
       CASE
       WHEN c2.RESULT_DETAIL IS NULL
            OR
            XMLEXISTS(
              '/RESULT_DETAIL/CLASS[not(text())][not(*)]'
              PASSING c2.RESULT_DETAIL
            )
       THEN 1
       ELSE 0
       END AS isClassEmpty,
       CASE WHEN Class IS NULL THEN 1 ELSE 0 END AS isClassEmpty2
FROM XML_TEST x
     LEFT OUTER JOIN
     XMLTABLE(
       '/Data/EMPLOYER'
       PASSING x.File_XML
       COLUMNS DOSSIER  NUMBER(8) PATH 'DOSSIER',
               SUMMARY  XMLTYPE   PATH 'SUMMARY'
     ) e
     ON ( 1 = 1 )
     LEFT OUTER JOIN
     XMLTABLE(
       '/SUMMARY'
       PASSING e.SUMMARY
       COLUMNS BEGINDATE DATE    PATH 'BEGINDATE',                            
               WORKER    XMLTYPE PATH 'WORKER'
     ) c1
     ON ( 1 = 1 )
     LEFT OUTER JOIN
     XMLTABLE(
       '/WORKER'
       PASSING c1.WORKER
       COLUMNS NRWORKER      NUMBER(7) PATH 'NRWORKER',                            
               RESULT_DETAIL XMLTYPE   PATH 'RESULT_DETAIL'
     ) c2
     ON ( 1 = 1 )
     LEFT OUTER JOIN
     XMLTABLE(
       '/RESULT_DETAIL'
       PASSING c2.RESULT_DETAIL
       COLUMNS CODE    CHAR(5)   PATH 'CODE',                            
               MINUTES NUMBER(5) PATH 'MINUTES',                            
               CLASS   CHAR(1)   PATH 'CLASS'                          
     ) c3
     ON ( 1 = 1 );

输出

档案 | 开始 | NR工人 | 代码 | 分钟 | 课程 | 分类 | 分类2
------: | :-------- | --------: | :---- | ------: | :---- | ------------: | ------------:
      1 | 19 年 2 月 13 日 | 42 | 12345 | 0 |   | 1 | 1
      2 | 19 年 2 月 14 日 | 1 | 98765 | 600 | 乙| 0 | 0
      3 | 19 年 2 月 14 日 | 7 |   |    |   | 1 | 1

db<>在这里摆弄

于 2019-02-13T15:41:10.680 回答