如何计算XQuery中的最长持续时间?
问题描述:
我在XQuery中有一个练习题。逻辑:如何计算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文件中的日期具有数字格式,而不是日期格式,因此,我正在尝试减去日期,如十进制数字。
答
您目前正在评估您的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]
答
如果你使用的撒克逊人,那么另一个选择是撒克逊:最高的功能:
saxon:highest(doc("LMSGI06")//course,
function($course) { $course/(end - start) }
)
但是,您使用十进制减法而不是日期/持续时间减法是不健全的。考虑2016031-20170101(一天:小数差= 8870)与20170201-20170205(四天:小数差= 4)的时间间隔。第二个持续时间较长,但有一个较小的小数差。所以你应该真正将值转换为xs:date,并将它们作为xs:date值减去以获得xs:duration值。
答
如果不使用撒克逊但仍然要处理每个course
只有一次,你可以重新实现saxon:highest(...)
功能纯的XQuery 3.0:
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)))
};
使用这两个函数,解决方案t o您的锻炼与正确的日期比较变得非常简单:
local:highest(
doc("LMSGI06")//course,
function($course) {
local:to-date($course/end) - local:to-date($course/start)
}
)