【问题标题】:XML Oracle : identify existing but empty elementXML Oracle:识别现有但为空的元素
【发布时间】:2019-07-07 04:40:36
【问题描述】:

我是使用 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 ;

【问题讨论】:

    标签: sql xml oracle


    【解决方案1】:

    您可以使用//[not(text())][not(*)]find elements without any text and without children

    所以在你的上下文中你可以使用:

    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你的表格,这样丢失的元素仍然会出现,然后你可以测试一下CLASS的值是否是NULL

    Oracle 设置

    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小提琴here

    【讨论】:

      【解决方案2】:

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

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

      查看how to write an XPATH query to check if a node is empty 的类似问题。

      -- 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 ;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-07
        • 2010-12-23
        • 1970-01-01
        • 2012-05-09
        • 2017-10-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多