【问题标题】:XQuery Most Recent Order for Each CustomerXQuery 每个客户的最近订单
【发布时间】:2014-03-06 21:57:20
【问题描述】:

我正在尝试使用 Altova XMLSpy 和 XQuery 1.0 返回每个客户的最新订单。

在 SQL 中查询是这样的:

SELECT `Order ID`, `Customer ID`, `Employee ID`, `Order Date`
FROM Orders AS O1
WHERE `Order Date` =
  (SELECT MAX(`Order Date`)
   FROM Orders AS O2
   WHERE O2.[Customer ID] = O1.[Customer ID]);

它返回 16 行,但我无法获得与在 XQuery 中工作类似的任何东西。

我尝试了多种代码变体,我认为最接近的是:

<result>
{
    for $cust in distinct-values(doc("Orders.xml")//Orders/Customer_x0020_ID)
    return
    <Customer>
    {
        for $order in doc("Orders.xml")//Orders
        where $cust = $order/Customer_x0020_ID
        return max(xs:string($order/Order_x0020_Date))

    }
    </Customer>

}
</result>

对于从 MS Access 导出 XML 的糟糕标签名称表示歉意。

请帮忙!提前致谢。

<Orders>
  <Order_x0020_ID>30</Order_x0020_ID>
  <Employee_x0020_ID>9</Employee_x0020_ID>
  <Customer_x0020_ID>27</Customer_x0020_ID>
  <Order_x0020_Date>2006-01-15T00:00:00</Order_x0020_Date>
</Orders>

编辑: 在尝试了 joemfb 的解决方案后,当我只需要最近(或最大日期)时,我会收到每个客户的所有订单:

<Customer>
    <Order_x0020_ID>57</Order_x0020_ID>
    <Customer_x0020_ID>27</Customer_x0020_ID>
    <Employee_x0020_ID>9</Employee_x0020_ID>
    <Order_x0020_Date>2006-04-22T00:00:00</Order_x0020_Date>
    <Order_x0020_ID>30</Order_x0020_ID>
    <Customer_x0020_ID>27</Customer_x0020_ID>
    <Employee_x0020_ID>9</Employee_x0020_ID>
    <Order_x0020_Date>2006-01-15T00:00:00</Order_x0020_Date>
</Customer>
<Customer>
    <Order_x0020_ID>80</Order_x0020_ID>
    <Customer_x0020_ID>4</Customer_x0020_ID>
    <Employee_x0020_ID>2</Employee_x0020_ID>
    <Order_x0020_Date>2006-04-25T17:03:55</Order_x0020_Date>
    <Order_x0020_ID>58</Order_x0020_ID>
    <Customer_x0020_ID>4</Customer_x0020_ID>
    <Employee_x0020_ID>3</Employee_x0020_ID>
    <Order_x0020_Date>2006-04-22T00:00:00</Order_x0020_Date>
    <Order_x0020_ID>61</Order_x0020_ID>
    <Customer_x0020_ID>4</Customer_x0020_ID>
    <Employee_x0020_ID>9</Employee_x0020_ID>
    <Order_x0020_Date>2006-04-07T00:00:00</Order_x0020_Date>
    <Order_x0020_ID>34</Order_x0020_ID>
    <Customer_x0020_ID>4</Customer_x0020_ID>
    <Employee_x0020_ID>9</Employee_x0020_ID>
    <Order_x0020_Date>2006-02-06T00:00:00</Order_x0020_Date>
    <Order_x0020_ID>31</Order_x0020_ID>
    <Customer_x0020_ID>4</Customer_x0020_ID>
    <Employee_x0020_ID>3</Employee_x0020_ID>
    <Order_x0020_Date>2006-01-20T00:00:00</Order_x0020_Date>
</Customer>

【问题讨论】:

  • 请始终提供示例数据以进行处理。由于对数据的误解,其他一切都只会导致一堆后续问题。
  • 您使用的是什么具体的数据库?他们都说“SQL”作为他们的查询语言——但是像 XML 支持这样的东西因供应商而异。因此,请使用您正在使用的具体数据库更新您的标签 - 无论是 MySQL、Postgres、Sybase、IBM DB2、Oracle、SQL Server、Interbase - 还是您正在使用的任何其他数据库!
  • 对于我使用 MS Access 但 XQuery 未使用数据库的 SQL,查询正在 Altova XMLSpy 中从独立的 XML 文档(我现在提供了一个 sn-p)中运行
  • 您的文件确定包含多个订单?如果有,如何表示多个订单?
  • @MichaelKay 是的,他们这样做了,XML 的命名很糟糕,因此提供的 sn-p 是针对一个订单的,而对于多个订单只是重复。这些包含在 节点中。

标签: mysql xml xquery xmlspy


【解决方案1】:

更新:我已修改查询以仅返回最近订单的所有元素。这个查询有点尴尬,因为您的源 XML 没有按顺序对元素进行分组。

<result>
{
  for $cust in distinct-values(doc("Orders.xml")//Orders/Customer_x0020_ID)
  return
    <Customer>
    {
      let $date :=
      (
        for $cid in doc("Orders.xml")//Orders/Customer_x0020_ID[. eq $cust]
        let $date := $cid/following-sibling::Order_x0020_Date[1]
        order by xs:dateTime($date) descending
        return $date
      )[1]
      return
      (
        $date/preceding-sibling::Order_x0020_ID[1],
        $date/preceding-sibling::Customer_x0020_ID[1],
        $date/preceding-sibling::Employee_x0020_ID[1],
        $date
      )
    }
    </Customer>
}
</result>

【讨论】:

  • 除了原来的SQL查询返回了Order IDCustomer IDEmployee IDOrder Date,而这里只返回日期。
  • 唉,它可以工作,但会返回每个客户的所有订单(将使用数据更新我的问题)。我只需要每个客户最近的订单,这就是我遇到的麻烦:(
  • 我花了一些时间试图弄清楚这个查询是如何工作的,但我很挣扎,尤其是let $date := $cid/following-sibling::Order_x0020_Date[1] 行和前面的兄弟位。希望我能得到一个解释?谢谢:)
【解决方案2】:

XQuery 3.0 解决方案。

像 saxon:highest() 这样的高阶函数在这里很有用:参见

http://www.saxonica.com/documentation/#!functions/saxon/highest

有了这样一个函数,代码就变成了下面的样子(我假设样本数据中的“Orders”元素代表一个订单,并且是重复的):

for $o in //Orders
group by $o/Customer_ID
return saxon:highest($o, function($order){xs:date($order/Order_Date)})

如果您不使用 Saxon,您可以自己编写 saxon:highest() 函数,如下所示:

declare function saxon:highest($s as item()*, $f as function(item()*) as xs:anyAtomicValue) as item()?{
  if (count($s) lt 2)
  then head($s)
  else (
      let $h := saxon:highest(tail($s), $f)
      return if ($f(head($s)) gt $f($h))
             then head($s)
             else $h
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多