目前我在查询SQL时遇到了困难。我有一个客户订单列表,我想根据某些标准删除一组客户订单:
因此,例如,如果客户在过去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天后排除客户的第一个订单。
任何帮助都将不胜感激。
答案 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