我在XQuery中练习有问题。逻辑:
这是xml文件的结构:
<training>
<course id="1">
<start>20170101</start>
<end>20170401</end>
</course>
</training>
我做到了:
for $x in doc("LMSGI06")//course
let $max := max($x/end - $x/start)
return
<duration>{$max}</duration>
这是我查询的结果:
<duration>300</duration>
<duration>400</duration>
<duration>400</duration>
<duration>400</duration>
<duration>10000</duration>
我的查询列出了所有课程的持续时间,但我只需要持续时间最长的课程。请注意,XML文件中的日期具有数字格式,而不是日期格式,因此,我尝试减去十进制数等日期。
答案 0 :(得分:3)
如果您正在使用Saxon,那么另一种选择是撒克逊人:最高职能:
saxon:highest(doc("LMSGI06")//course,
function($course) { $course/(end - start) }
)
但是,使用十进制减法而不是日期/持续时间减法并不是合理的。考虑间隔20161231-20170101(一天:小数差= 8870)与20170201-20170205(四天:小数差= 4)。第二个持续时间较长,但小数差较小。因此,您应该将值真正转换为xs:date,并将它们减去xs:date值以获取xs:duration值。
答案 1 :(得分:2)
您目前正在评估for循环中的max()
。单个数字的max()
就是那个数字。
您可以获得所有持续时间的max()
,然后选择具有该持续时间的课程:
let $doc := doc("LMSGI06")
let $maxDuration := max(
for $x in $doc//course
return $x/end - $x/start
)
return $doc//course[(end - start) eq $maxDuration]
或者您可以按照其持续时间订购课程,然后选择第一个:
(
for $course in doc("LMSGI06")//course
order by $course/end - $course/start descending
return $course
)[1]
答案 2 :(得分:2)
如果您不使用 Saxon 但仍希望仅处理每个course
一次,则可以重新实现纯 XQuery 3.0中的saxon:highest(...)
函数:
declare function local:highest($seq, $key-func) {
head(
fold-left($seq, (),
function($max, $curr) {
let $key := $key-func($curr)
return if($max[2] >= $key) then $max else ($curr, $key)
}
)
)
};
可以将日期字符串转换为xs:date
数据类型,如下所示:
declare function local:to-date($str) {
xs:date(concat(substring($str, 1, 4), '-',
substring($str, 5, 2), '-', substring($str, 7)))
};
使用这两个功能,正确的日期比较练习的解决方案变得非常简单:
local:highest(
doc("LMSGI06")//course,
function($course) {
local:to-date($course/end) - local:to-date($course/start)
}
)