Найти дубликаты дочерних узлов в Oracle - PullRequest
1 голос
/ 18 октября 2019

У меня есть столбец в базе данных oracle, в котором хранятся данные XML.

По какой-то причине мой запрос не проверял существующие узлы при его вставке и, следовательно, вызвал дублирование узлов в нескольких строках.

Я не могу найти эффективный способ найти эти дубликаты.

Мой XML выглядит следующим образом:

<myroot>
  <mydata>

    <myusers>
      <username>amy</username>
      <userrole/>
      <userrole>junior artist</userrole>
    </myusers>

    <myusers>
      <username>rosy</username>
      <userrole/>
      <userrole>junior artist</userrole>
    </myusers>

    <myusers>
      <username>timmy</username>
      <userrole>junior artist</userrole>
    </myusers>

  </mydata>
</myroot>

Как показано в приведенном выше примере XML, пустой узел сидитпростаивают в нескольких тегах из нескольких строк, но есть ли способ, которым я могу просто найти, какие строки содержат дубликаты?

Раньше я использовал запрос ниже, чтобы просто извлечь эти данные, но не знаю, как извлечь данные издва:

SELECT MYID, EXTRACT(MYDATA, 'myroot/mydata/myusers/userole/text()') 
FROM MYTABLE 
WHERE
EXISTNODE(MYDATA, 'myroot/mydata/myusers/userole') = 1

Просто для фона, мой другой запрос извлечения данных не отправляет ниже ошибка, причина, по которой теперь необходимо исправить вышеуказанные данные:

ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence

Ответы [ 2 ]

1 голос
/ 19 октября 2019

Подумайте об использовании «XMLTABLE» вместо других, теперь устаревших функций «EXTRACT».

Если у вас есть XML в таблице, которую я буду называть «tbl» в моем примере ниже, выможет сделать это так:

with tbl as
(
    select
        XMLType(
        '<myroot>
          <mydata>

            <myusers>
              <username>amy</username>
              <userrole/>
              <userrole>junior artist</userrole>
            </myusers>

            <myusers>
              <username>rosy</username>
              <userrole/>
              <userrole>junior artist</userrole>
            </myusers>

            <myusers>
              <username>timmy</username>
              <userrole>junior artist</userrole>
            </myusers>

          </mydata>
        </myroot>'
        ) xmldata
    from
        dual
)
select username, userrole
from (
    select username, userrole, count(*) over ( partition by username) rolecnt
    from   tbl,
           xmltable('/myroot/mydata/myusers/userrole' 
                          PASSING tbl.xmldata 
                          COLUMNS username VARCHAR2(80) PATH './../username', 
                                  userrole VARCHAR2(80) PATH '.')
    )
where rolecnt > 1
+----------+---------------+
| USERNAME |   USERROLE    |
+----------+---------------+
| amy      |               |
| amy      | junior artist |
| rosy     |               |
| rosy     | junior artist |
+----------+---------------+

NB Я предположил, что «userole» в ваших входных данных был опечаткой, и вы имеете в виду «userrole».

0 голосов
/ 22 октября 2019

Что мне в итоге помогло, так это выяснить количество тегов «myusers» и «userrole». Везде, где подсчет был несоответствующим, были строки, которые требовали внимания. У меня было 2000 строк, и у двух из них был дубликат, так что это решение отлично работало для меня. Но если бы это был другой набор данных, я думаю, что решение @Matthew McPeak будет работать отлично.

Я уверен, что могут быть более эффективные и эффективные способы сделать это, но ниже приведен разовый запрос, который работал нормальнодля меня.

SELECT * FROM 
    (
    select count(*) MYCON, MYID
        from MYTABLE  sa
        cross join xmltable('myroot/mydata/myusers'
            passing sa.MYDATA columns myusers varchar2(1) path '@dummy'
    ) 
    GROUP BY MYID ) BB
JOIN
    (
    select count(*) YOURCON, MYID
        from MYTABLE sa
        cross join xmltable('myroot/mydata/myusers/userrole'
            passing sa.MYDATA columns myusers varchar2(1) path '@dummy'
    ) 
    GROUP BY MYID ) AA
ON  AA.MYID = BB.MYID
WHERE MYCON <> YOURCON
...