从客户订单表中查找最近的重复订单 - 慢速交叉应用

Posted

技术标签:

【中文标题】从客户订单表中查找最近的重复订单 - 慢速交叉应用【英文标题】:Finding the most recent order duplicate from a customer order table - SLOW CROSS APPLY 【发布时间】:2021-06-16 17:37:01 【问题描述】:

我只想显示客户订购了相同商品的订单,但只显示之前下达的最近完成的订单。

我想为同一客户、同一商品获得最直接的订单。就像显示重复的一样,但只是最近的。

查询在完成我想要它做的事情时工作正常,但是当我将交叉应用添加到我的实际查询时,它会减慢很多。

编辑:我也尝试过 select top 1 而不是使用行号。 rownumber 行使其仅快 1 秒。

declare @orders as table (
    ord_id numeric(7,0),
    customer_id numeric(4,0),
    order_time datetime,
    item_id numeric (4,0),
    status int NOT NULL
)

insert into @orders values
(1516235,5116,'06/04/2021 11:06:00', 5616, 1),
(1516236,5116,'06/03/2021 13:51:00', 5616, 1),
(1514586,5554,'06/01/2021 08:16:00', 5616, 1),
(1516288,5554,'06/01/2021 15:35:00', 5616, 1),
(1516241,5554,'06/04/2021 11:11:00', 4862, 1),
(1516778,5554,'06/04/2021 11:05:00', 4862, 2)

select distinct *
from @orders o
cross apply (
    select a.ord_id, row_number() over (partition by a.customer_id order by a.order_time) as rownum
    from @orders a 
    where a.customer_id = o.customer_id and
    a.status != 2 and
    a.item_id = o.item_id and
    a.order_time < o.order_time
)a

where a.rownum = 1

还有其他方法可以做到这一点吗?如何加快速度?

之前的订单必须有

    在其他订单之前的一个订单时间 相同的客户记录 相同的物品记录 之前所有其他记录中的最新记录 状态为已取消(1 = 完成;2 = 已取消)

【问题讨论】:

a.status != 2 这不符合您的要求,尽管您以两种相互冲突的方式陈述它。您想要“已完成”的订单,或者您想要“未取消”的订单。在某个时候添加另一个状态值,您当前的逻辑(以及您的第二个需求版本)就会崩溃。大概 status 也可以是 NULL - 这是另一个状态值,幸运的是,它被您的逻辑排除在外。 变量表只能串行运行。如果您有大量数据,也许临时表会是更好的解决方案? CTE 也可能对您有用,因为您可以在其中进行排名并从中进行选择。 CTE 也会利用源表上的索引 您使用的是哪个版本的 SQL Server? @Eli 我正在使用 v18.8 @SMor 在这个例子中,只有两个,不能为空。我将编辑帖子以反映这一点。 【参考方案1】:

这很愚蠢。这是使用cross apply的更简单的方法:

select o.*
from @orders o cross apply
     (select top (1) a.ord_id
      from @orders a 
      where a.customer_id = o.customer_id and
            a.status <> 2 and
            a.item_id = o.item_id and
            a.order_time < o.order_time
      order by a.order_time
     ) a;

这可以使用(customer_id, item_id, status, order_time) 上的索引。

注意:如果您想要上一个订单中最新的,那么order by 应该使用desc。但是,问题中的代码不是这样表述的。

而且,您应该能够使用窗口函数。如果ord_id随时间增加:

min(case when status <> 2 then ord_id end) over (partition by customer_id, item_id)

即使这不是真的,也有变化,但由于过滤状态,它更复杂(即需要子查询)。

【讨论】:

是的,我最初已经这样做了。 row_number() 行使它快了 1 秒。仍然需要 25 秒来加载查询。 @Gordon Linoff 在示例数据中提供了每个客户/订单排列只有 2 条记录;您在代码中的哪个位置阻止显示多个先前的订单? @eli 。 . . select top (1). @GordonLinoff 查询运行的时间与 min() 的东西差不多。我会考虑使用索引。谢谢 @GordonLinoff 当我编写我的代码时,顺序是在选择语句“row_number() over (partition by a.customer_id order by a.order_time)”中,如果我按 order_time 排序了解您的编辑权

以上是关于从客户订单表中查找最近的重复订单 - 慢速交叉应用的主要内容,如果未能解决你的问题,请参考以下文章

SQL的一些查询语句

具有交叉应用语法的先前记录

如何通过特定日期的唯一客户和重复客户获取每天的客户数量?

来自选择查询的一个单元格中的多个值

查找Salesperson第二高的销售SQL

查找两个最近订单之间的时差