在 Oracle 中查找重复的子节点
Posted
技术标签:
【中文标题】在 Oracle 中查找重复的子节点【英文标题】:Find duplicate child nodes in Oracle 【发布时间】:2019-10-18 20:50:54 【问题描述】:我在 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
【问题讨论】:
是的,更正了错字。用户角色重复。 【参考方案1】:考虑使用“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 | +----------+---------------+
注意我假设您输入数据中的“userole”是一个错字,而您的意思是“userrole”。
【讨论】:
我喜欢您的解决方案,它在示例中运行良好,但是当我在数据库值上运行时,用户名从未显示任何值。它总是一片空白。所以我找到了另一种适用于我的数据集的方法。【参考方案2】:最终对我有用的是找出“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
【讨论】:
以上是关于在 Oracle 中查找重复的子节点的主要内容,如果未能解决你的问题,请参考以下文章