如何计算XQuery中的最长持续时间?

如何计算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) 
    } 
)