SQL以最小金额获取超过特定日期的记录

时间:2016-10-19 23:32:10

标签: sql sql-server sql-server-2012

目前我在查询SQL时遇到了困难。我有一个客户订单列表,我想根据某些标准删除一组客户订单:

  1. 我们需要保留每位客户过去订单中的至少6个。
  2. 我们需要保留过去90天内发生的所有客户订单。
  3. 我们需要保留每个客户超过90天的订单中的至少1个(如果客户在过去90天内有4个订单,我们需要保留2个以前的订单才能达到6个订单要求。
  4. 因此,例如,如果客户在过去90天内有6个订单,我们会保留7个订单(因为我们包含了超过90天的1个订单)。

    如果客户在过去90天内有21个订单,我们会保留22个订单。

    如果客户在过去90天内有5个订单,我们会保留6个订单。

    以下是我用来构建订单表的查询:

    INSERT INTO @OrdersToDelete
    SELECT TempOrders.Site, TempOrders.Number, TempOrders.RowNumber, TempOrders.CustomerNumber
    FROM (SELECT
            ROW_NUMBER() OVER ( PARTITION BY CustomerNumber ORDER BY OrderDate DESC) AS 'RowNumber',
            Number,
            OrderDate,
            CustomerNumber
        FROM Orders
    ) TempOrders
    LEFT OUTER JOIN (SELECT
            ROW_NUMBER() OVER ( PARTITION BY CustomerNumber ORDER BY OrderDate DESC) AS 'RowNumber',
            Number,
            CustomerNumber
        FROM SmartOrders
    ) SmartOrderOrders
        ON TempOrders.Site = SmartOrderOrders.Site
            AND TempOrders.Number = SmartOrderOrders.Number
        WHERE
            (DATEDIFF(dd, OrderDate, GETDATE()) > 90
    

    此查询返回已删除的订单列表(超过90天)。在WHERE子句中,我也可以检查订单号,但是我很难弄清楚如何在90天后排除客户的第一个订单。

    任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:1)

--Get the rownumbers using a case expression in order by 
--so all the orders within the last 90 days come first
WITH ROWNUMS AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY CustomerNumber 
                   ORDER BY 
                   CASE WHEN DATEDIFF(dd, OrderDate, GETDATE()) < 90 THEN 1 ELSE 0 END DESC, 
                   OrderDate DESC) AS 'RowNumber',
Number,
OrderDate,
CustomerNumber
FROM Orders) 
--Get the maximum rownumber per customer in the last 90 days
,MAXROWNUM AS (select CustomerNumber, MAX(rn) maxrn from ROWNUMS 
               where diff<=90 
               group by id)
--Join the previous cte's and get all the orders for a customer in the last 90 days
-- + one more row which is the latest before 90 days
SELECT r.* 
FROM ROWNUMS r
JOIN MAXROWNUM c ON c.CustomerNumber=r.CustomerNumber
WHERE r.rn <= c.maxrn+1 
--use r.rn <= case when c.maxrn <=5 then 5 else c.maxrn end + 1 to get atleast 6 orders per customer

答案 1 :(得分:1)

给这一点。

首先创建3个公用表格表达式(CTE)。您可以将它们作为嵌套子查询来执行,但我发现CTE更易于阅读和管理,而且它们更容易解释。

WITH ninety_day_cte
AS
(SELECT temporders.site, temporders.number, temporders.customernumber, temporders.orderdate
FROM orders
WHERE
    temporders.orderdate >= DATEADD(DAY,-ninety,GETDATE())),

ninety_day_count_cte
AS
(SELECT temporders.customernumber, COUNT(*) AS Order_Count
FROM orders
WHERE
    temporders.orderdate >= DATEADD(DAY,-ninety,GETDATE())
GROUP BY
    temporders.customernumber),

greater_ninety_day_cte
AS
(SELECT temporders.site, temporders.number, temporders.customernumber, temporders.orderdate,
    ROW_NUMBER() OVER(PARTITION BY temporders.customernumber ORDER BY temporders.orderdate DESC) AS Row_Number
FROM orders
WHERE
    temporders.orderdate < DATEADD(DAY,-ninety,GETDATE()))

第一个CTE ninety_day_cte 将在过去90天内获取所有订单 - 我们需要为所有客户提供此订单,我们需要所有订单。很简单,我们可以把它放在一边。

第二个CTE ninety_day_count_cte 用于确定过去90天内每位客户的订单总数。我们需要知道这个数字,以确定我们需要抓取超过90天的订单数量。

第三个CTE greater_ninety_day_cte 将获取超过90天的所有订单。我们添加ROW_NUMBER()按订单日期对每位客户的订单进行排名 - 这将有助于我们获取过去90天所需的订单。

现在我们需要添加将获取过去90天订单的查询:

SELECT site, number, customernumber, orderdate
FROM greater_ninety_day_cte AS g
LEFT JOIN ninety_day_count AS c
ON g.customernumber = c.customernumber
WHERE
    g.Row_Number <= CASE
                WHEN  CASE WHEN c.Order_Count IS NULL THEN 0 ELSE c.Order_Count END > 6 THEN 1
                ELSE (6 - CASE WHEN c.Order_Count IS NULL THEN 0 ELSE c.Order_Count END)
            END

这使用第2和第3个CTE。我们使用LEFT JOIN,因此我们为只有90天以上订单的客户获取数据。 WHERE子句从第3个CTE获取Row_Number,并将其与第2个CTE中的Order_Count进行比较。 CASE条款规定,如果Order_Count(过去90天的订单数量)大于6,我们只想拉动Row_Number&gt; = 1,但如果Order_Count小于6,那么我们想要拉差( 6 - Order_Count)。这应该可以获得满足要求的所有超过90天的订单。

现在我们只需要获得少于90天的订单。使用第一个CTE:

使用UNION ALL语句可以轻松完成此操作
UNION ALL
SELECT site, number, customernumber, orderdate
FROM ninety_day_cte

那应该可以得到你需要的所有结果。至少6个订单,至少1个订单超过90天。

以下是完整的查询:

WITH ninety_day_cte
AS
(SELECT temporders.site, temporders.number, temporders.customernumber, temporders.orderdate
FROM orders
WHERE
    temporders.orderdate >= DATEADD(DAY,-ninety,GETDATE())),

ninety_day_count_cte
AS
(SELECT temporders.customernumber, COUNT(*) AS Order_Count
FROM orders
WHERE
    temporders.orderdate >= DATEADD(DAY,-ninety,GETDATE())
GROUP BY
    temporders.customernumber),

greater_ninety_day_cte
AS
(SELECT temporders.site, temporders.number, temporders.customernumber, temporders.orderdate,
    ROW_NUMBER() OVER(PARTITION BY temporders.customernumber ORDER BY temporders.orderdate DESC) AS Row_Number
FROM orders
WHERE
    temporders.orderdate < DATEADD(DAY,-ninety,GETDATE()))

SELECT site, number, customernumber, orderdate
FROM greater_ninety_day_cte AS g
LEFT JOIN ninety_day_count AS c
ON g.customernumber = c.customernumber
WHERE
    g.Row_Number <= CASE
                WHEN  CASE WHEN c.Order_Count IS NULL THEN 0 ELSE c.Order_Count END > 6 THEN 1
                ELSE (6 - CASE WHEN c.Order_Count IS NULL THEN 0 ELSE c.Order_Count END)
            END
UNION ALL
SELECT site, number, customernumber, orderdate
FROM ninety_day_cte