XML Oracle: определить существующий, но пустой элемент - PullRequest
0 голосов
/ 13 февраля 2019

Я новичок в xml DB с Oracle, и я начинаю разбираться в этом, но есть одна вещь, которую я не могу понять: важно мне определить, 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 ;

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Вы можете использовать //[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 ваши таблицы, чтобы отсутствующие элементы все еще появлялись, и тогда вы можете просто проверить, является ли значение CLASS NULL:

Oracle Setup :

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

Выход :

DOSSIER | BEGINDATE | NRWORKER | CODE  | MINUTES | CLASS | ISCLASSEMPTY | ISCLASSEMPTY2
------: | :-------- | -------: | :---- | ------: | :---- | -----------: | ------------:
      1 | 13-FEB-19 |       42 | 12345 |       0 | <em>null</em>  |            1 |             1
      2 | 14-FEB-19 |        1 | 98765 |     600 | B     |            0 |             0
      3 | 14-FEB-19 |        7 | <em>null</em>  |    <em>null</em> | <em>null</em>  |            1 |             1

db <> Fiddle здесь

0 голосов
/ 13 февраля 2019

XMLEXISTS возвращает true для пустых элементов, вы просто отправляете его c3.CLASS, который является столбцом CHAR(1) вместо XMLTYPE, поэтому он не обнаруживает корневой элемент (/) и возвращает false.

Вот пример различных способов, которыми вы можете поэкспериментировать с этим.Я добавил XMLTYPE копию CLASS в c3 и сослался на нее в предложении SELECT.Попробуйте удалить "z" из данных примера или всего узла CLASS и посмотрите, что произойдет.

Смотрите этот похожий вопрос для как написать запрос 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 ;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...