【问题标题】:XQuery - Doing math on elements within a sequence and aggregating resultsXQuery - 对序列中的元素进行数学运算并聚合结果
【发布时间】:2015-08-31 05:15:12
【问题描述】:

我试图在两个 XML 元素的乘法中执行 XQuery 求和函数,但很难避免元素序列中的迭代。例如,考虑这种情况:

样本数据:

<Orders>
     <Order>
        <OrderKey>1</OrderKey>
        <LineItem>
          <LineNumber>1</LineNumber>
          <Quantity>41</Quantity>
          <ExtendedPrice>70848.0000</ExtendedPrice>
          <Discount>0.0913</Discount>
          <Tax>0.0663</Tax>
          <ReturnFlag>A</ReturnFlag>
          <LineStatus>F</LineStatus>
          <ShipDate>1994-09-03</ShipDate>
        </LineItem>
        <LineItem>
          <LineNumber>2</LineNumber>
          <Quantity>44</Quantity>
          <ExtendedPrice>64372.0000</ExtendedPrice>
          <Discount>0.0674</Discount>
          <Tax>0.0145</Tax>
          <ReturnFlag>A</ReturnFlag>
          <LineStatus>F</LineStatus>
          <ShipDate>1994-08-18</ShipDate>
        </LineItem>
        <LineItem>
          <LineNumber>3</LineNumber>
          <Quantity>41</Quantity>
          <ExtendedPrice>64247.0000</ExtendedPrice>
          <Discount>0.0396</Discount>
          <Tax>0.0466</Tax>
          <ReturnFlag>R</ReturnFlag>
          <LineStatus>F</LineStatus>
          <ShipDate>1994-10-21</ShipDate>
        </LineItem>
      </Order>
      . . . 
</Orders>

XQuery:

<results> {
   for $lineitem in collection("tpch")/Orders/Order/LineItem
   let $returnflag := $lineitem/ReturnFlag 
   let $linestatus := $lineitem/LineStatus
   where $lineitem/ShipDate <= "1998-08-31"
   group by $returnflag, $linestatus
   order by $returnflag, $linestatus
   return
   <record>
      <l_returnflag>{$returnflag}</l_returnflag>
      <l_linestatus>{$linestatus}</l_linestatus>
      <sum_qty>{sum($lineitem/Quantity)}</sum_qty>
      <sum_base_price>{sum($lineitem/ExtendedPrice)}</sum_base_price>
      <sum_disc_price>{sum($lineitem/ExtendedPrice*(1-$lineitem/Discount))}</sum_disc_price>
      <sum_charge>{sum($lineitem/ExtendedPrice*(1-$lineitem/Discount)*(1+$lineitem/Tax))}</sum_charge>
      <avg_qt>{avg($lineitem/Quantity)}</avg_qt>
      <avg_price>{avg($lineitem/ExtendedPrice)}</avg_price>
      <avg_disc>{avg($lineitem/Discount)}</avg_disc>
      <count_order>{count($lineitem)}</count_order>
   </record>
} </results>

BaseX 输出:

[XPTY0004] 预期项目,找到序列:(元素 ExtendedPrice {...},......

当我删除“sum_disc_price ...”和“sum_charge ...”结果行时,查询运行正常。

我的问题: 考虑到这个数据集模型,我怎样才能在不改变其语义的情况下编写这个查询?

【问题讨论】:

  • 仅供参考,您可以使用 declare context element 将您的数据放入您的 XQuery,以便人们可以将某些内容作为单个文档复制/粘贴/运行。
  • ...复制/粘贴/运行也意味着将collection() 取出。
  • 实际上 -- group by 也把你搞砸了,因为这意味着 $lineitem 一次可以引用多个 LineItem。当$lineitem/Discount 同时指代两个单独的折扣时,我不知道您会如何期望您的数学运算。

标签: function operators xquery sequence aggregation


【解决方案1】:

发生错误是因为您使用的运算(如乘法)恰好采用两个参数,并在一侧或两侧传递一个序列。为了说明错误的含义——你得到完全相同的东西运行:

(1,2,3) * 2

由于您的目标是在聚合结果之前将 $lineitem 序列内的每个 LineItem 中的值相乘(这是由于 group by 运算符而产生的序列),因此您可以使用fn:for-each-pair。使用匿名函数实现,可能会执行以下操作:

      <sum_disc_price>{sum(fn:for-each-pair(
        $lineitem/ExtendedPrice, $lineitem/Discount,
         function ($price, $discount) as xs:double {
           xs:double($price) * (1 - xs:double($discount))
         }(?,?)))}</sum_disc_price>

【讨论】:

  • 这没有意义,因为没有 group by 查询结合了所有可能性。我只需要列出所有 LineItems 的折扣扩展价格和折扣扩展价格加税的总和。
  • 你需要从你做单项数学的地方分开你在哪里做你的小组数学(平均等)。先对单个项目进行数学运算,然后迭代计算结果,然后再进行分组和聚合。
  • 毕竟,当ExtendedPriceDiscount 都是具有多个项目的序列时,乘以ExtendedPrice * Discount 没有意义。当然,您希望将 ExtendedPrice 的第一个元素与 Discount 的第一个元素相乘,第二个与第二个元素相乘,以此类推;但是系统还有很多其他的解释方式,所以语言不允许这样做:你需要编写代码来消除歧义。
  • @LuizMatos, ...实际上,fn:for-each-pair 可能就是你想要的。
  • 它可以工作(无需取出 group by)!谢谢@CharlesDuffy。
猜你喜欢
  • 1970-01-01
  • 2014-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2019-07-12
相关资源
最近更新 更多