了解 XQuery 中的联接
Understanding joins in XQuery
我有两个 XML 文档要使用 XQuery 加入。我知道数据包含一些重复条目。
test1.xml
<marc:collection
xmlns:marc="http://www.loc.gov/MARC21/slim">
<marc:record>
<marc:leader>01225cam a2200373Mi 4500</marc:leader>
<marc:controlfield tag="001">5323084</marc:controlfield>
<marc:datafield
ind1="1"
ind2="4"
tag="245">
<marc:subfield code="a">Els teleclubs a les illes Balears :</marc:subfield>
</marc:datafield>
</marc:record>
<marc:record>
<marc:leader>01225cam a2200373Mi 4500</marc:leader>
<marc:controlfield tag="001">5323084</marc:controlfield>
<marc:datafield
ind1="1"
ind2="4"
tag="245">
<marc:subfield code="a">Els teleclubs a les illes Balears :</marc:subfield>
</marc:datafield>
</marc:record>
<marc:record>
<marc:leader>00818cam a2200241Mi 4500</marc:leader>
<marc:controlfield tag="001">6310976</marc:controlfield>
<marc:datafield
ind1="0"
ind2="0"
tag="245">
<marc:subfield code="a">Diccionari manual de sinònims i antònims de la llengua catalana /</marc:subfield>
</marc:datafield>
</marc:record>
</marc:collection>
test2.xml
<root>
<row>
<LANGUAGE>cat</LANGUAGE>
<ITEM_ID>5912416</ITEM_ID>
<BIB_ID>5323084</BIB_ID>
<VENDOR_CODE>MXBKSMX</VENDOR_CODE>
</row>
<row>
<LANGUAGE>cat</LANGUAGE>
<ITEM_ID>5912416</ITEM_ID>
<BIB_ID>5323084</BIB_ID>
<VENDOR_CODE>PUVILL</VENDOR_CODE>
</row>
<row>
<LANGUAGE>cat</LANGUAGE>
<ITEM_ID>5935043</ITEM_ID>
<BIB_ID>6310976</BIB_ID>
<VENDOR_CODE>PUVILL</VENDOR_CODE>
</row>
</root>
我正在尝试使用来自 test1.xml
的 marc:controlfield[@tag = '001']
的值和来自 test2.xml
的 BIB_ID
的值进行简单连接。
XQuery
xquery version "3.0";
declare namespace marc="http://www.loc.gov/MARC21/slim";
for $m in doc("test1.xml")/marc:collection/marc:record,
$r in doc("test2.xml")/root/row[BIB_ID = $m/marc:controlfield[@tag = '001']]
return
<test n="{$r/ITEM_ID}">{
$m/marc:datafield[@tag = '245']/marc:subfield[@code = 'a']/string()
}</test>
当我 运行 这样做时,我得到了前两个匹配项的重复值:
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5935043">Diccionari manual de sinònims i antònims de la llengua catalana /</test>
我可以通过添加 group by
子句来解决这个问题:
for $m in doc("test2.xml")/marc:collection/marc:record,
$r in doc("test1.xml")/root/row[BIB_ID = $m/marc:controlfield[@tag = '001']]
group by $key := $r/ITEM_ID
return
<test c="{$key}">{
$m/marc:datafield[@tag = '245']/marc:subfield[@code = 'a']/string()
}</test>
结果
<test c="5912416">Els teleclubs a les illes Balears : Els teleclubs a les illes Balears :</test>
<test c="5935043">Diccionari manual de sinònims i antònims de la llengua catalana /</test
但我想了解为什么在第一种情况下,每个 for
子句都会重复重复的条目。为什么第二个 for
子句中的谓词在发生连接时不过滤掉重复的值?如果我确实想保留重复的条目(没有不需要的重复),最好的方法是什么?
这是预期的行为,在 SQL JOIN 中可以观察到类似的效果。当用于 JOIN 的键不唯一时,您将获得具有匹配键的所有数据的 笛卡尔积。
例如在这种情况下,有 2 个 <row>
个元素 BIB_ID
在第一个 XML 中等于 5323084
,并且有 2 个 <marc:record>
在第二个 XML 中匹配该值的元素。因此,当将 2 行数据与另外 2 行数据配对时,结果是所有可能的组合(参见插图*),这会产生 4 种可能的组合 (2 x 2),正如您在 XQuery 结果中观察到的那样。
*: 该图其实是用source article中的CROSS JOIN来说明的,但是效果是一样的
许多 XPath XQuery 表达式消除了相同节点不会在结果中出现两次的意义上的重复节点,但是没有消除节点深度相等(所有子节点、后代节点)的表达式, 属性相同).
我对这个问题的直觉是在进行连接之前从输入中消除重复项,而不是从结果中消除它们。
"And if I did want to preserve the duplicate entries (without the
unwanted repetition), what would be the best approach?"
根据我的经验,在这种情况下,您通常需要树结构作为结果,而不是平面结果,因此您必须将关系思维抛到脑后。你通常会得到类似
的表达式
for $i in $input return
<parent value="{$i/something}">{
for $j in $anotherInput[$j/xyz = $i/abc] return
<child value="{$j/something}"> {
f($i, $j)
}</child>
}</parent>
我有两个 XML 文档要使用 XQuery 加入。我知道数据包含一些重复条目。
test1.xml
<marc:collection
xmlns:marc="http://www.loc.gov/MARC21/slim">
<marc:record>
<marc:leader>01225cam a2200373Mi 4500</marc:leader>
<marc:controlfield tag="001">5323084</marc:controlfield>
<marc:datafield
ind1="1"
ind2="4"
tag="245">
<marc:subfield code="a">Els teleclubs a les illes Balears :</marc:subfield>
</marc:datafield>
</marc:record>
<marc:record>
<marc:leader>01225cam a2200373Mi 4500</marc:leader>
<marc:controlfield tag="001">5323084</marc:controlfield>
<marc:datafield
ind1="1"
ind2="4"
tag="245">
<marc:subfield code="a">Els teleclubs a les illes Balears :</marc:subfield>
</marc:datafield>
</marc:record>
<marc:record>
<marc:leader>00818cam a2200241Mi 4500</marc:leader>
<marc:controlfield tag="001">6310976</marc:controlfield>
<marc:datafield
ind1="0"
ind2="0"
tag="245">
<marc:subfield code="a">Diccionari manual de sinònims i antònims de la llengua catalana /</marc:subfield>
</marc:datafield>
</marc:record>
</marc:collection>
test2.xml
<root>
<row>
<LANGUAGE>cat</LANGUAGE>
<ITEM_ID>5912416</ITEM_ID>
<BIB_ID>5323084</BIB_ID>
<VENDOR_CODE>MXBKSMX</VENDOR_CODE>
</row>
<row>
<LANGUAGE>cat</LANGUAGE>
<ITEM_ID>5912416</ITEM_ID>
<BIB_ID>5323084</BIB_ID>
<VENDOR_CODE>PUVILL</VENDOR_CODE>
</row>
<row>
<LANGUAGE>cat</LANGUAGE>
<ITEM_ID>5935043</ITEM_ID>
<BIB_ID>6310976</BIB_ID>
<VENDOR_CODE>PUVILL</VENDOR_CODE>
</row>
</root>
我正在尝试使用来自 test1.xml
的 marc:controlfield[@tag = '001']
的值和来自 test2.xml
的 BIB_ID
的值进行简单连接。
XQuery
xquery version "3.0";
declare namespace marc="http://www.loc.gov/MARC21/slim";
for $m in doc("test1.xml")/marc:collection/marc:record,
$r in doc("test2.xml")/root/row[BIB_ID = $m/marc:controlfield[@tag = '001']]
return
<test n="{$r/ITEM_ID}">{
$m/marc:datafield[@tag = '245']/marc:subfield[@code = 'a']/string()
}</test>
当我 运行 这样做时,我得到了前两个匹配项的重复值:
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5912416">Els teleclubs a les illes Balears :</test>
<test n="5935043">Diccionari manual de sinònims i antònims de la llengua catalana /</test>
我可以通过添加 group by
子句来解决这个问题:
for $m in doc("test2.xml")/marc:collection/marc:record,
$r in doc("test1.xml")/root/row[BIB_ID = $m/marc:controlfield[@tag = '001']]
group by $key := $r/ITEM_ID
return
<test c="{$key}">{
$m/marc:datafield[@tag = '245']/marc:subfield[@code = 'a']/string()
}</test>
结果
<test c="5912416">Els teleclubs a les illes Balears : Els teleclubs a les illes Balears :</test>
<test c="5935043">Diccionari manual de sinònims i antònims de la llengua catalana /</test
但我想了解为什么在第一种情况下,每个 for
子句都会重复重复的条目。为什么第二个 for
子句中的谓词在发生连接时不过滤掉重复的值?如果我确实想保留重复的条目(没有不需要的重复),最好的方法是什么?
这是预期的行为,在 SQL JOIN 中可以观察到类似的效果。当用于 JOIN 的键不唯一时,您将获得具有匹配键的所有数据的 笛卡尔积。
例如在这种情况下,有 2 个 <row>
个元素 BIB_ID
在第一个 XML 中等于 5323084
,并且有 2 个 <marc:record>
在第二个 XML 中匹配该值的元素。因此,当将 2 行数据与另外 2 行数据配对时,结果是所有可能的组合(参见插图*),这会产生 4 种可能的组合 (2 x 2),正如您在 XQuery 结果中观察到的那样。
*: 该图其实是用source article中的CROSS JOIN来说明的,但是效果是一样的
许多 XPath XQuery 表达式消除了相同节点不会在结果中出现两次的意义上的重复节点,但是没有消除节点深度相等(所有子节点、后代节点)的表达式, 属性相同).
我对这个问题的直觉是在进行连接之前从输入中消除重复项,而不是从结果中消除它们。
"And if I did want to preserve the duplicate entries (without the unwanted repetition), what would be the best approach?"
根据我的经验,在这种情况下,您通常需要树结构作为结果,而不是平面结果,因此您必须将关系思维抛到脑后。你通常会得到类似
的表达式for $i in $input return
<parent value="{$i/something}">{
for $j in $anotherInput[$j/xyz = $i/abc] return
<child value="{$j/something}"> {
f($i, $j)
}</child>
}</parent>