2016-11-24 66 views
0

使用AdventureWorks2014 db,我想要选择以下数据:对于每位客户,我希望从他的第一笔订单起,在12个月内完成所有订单。我结束了解决方案:SQL分组数据

WITH dates AS 
(
SELECT soh.CustomerID 
    ,MIN(soh.OrderDate) AS MinOrderDate 
    ,DATEADD(MONTH, 12, MIN(soh.OrderDate)) as MaxOrderDate 
FROM Sales.SalesOrderHeader soh 
JOIN Sales.SalesOrderDetail sod ON sod.SalesOrderID=soh.SalesOrderID 
GROUP BY soh.CustomerID 
) 

SELECT soh.CustomerID 
    ,soh.OrderDate 
    ,sod.ProductID 
FROM Sales.SalesOrderHeader soh 
JOIN Sales.SalesOrderDetail sod ON sod.SalesOrderID=soh.SalesOrderID 
JOIN dates on dates.CustomerID=soh.CustomerID 
WHERE soh.OrderDate BETWEEN MinOrderDate AND MaxOrderDate 
ORDER BY soh.CustomerID 

不知道这是否正确?我想知道是否有更简单的解决方案?

回答

1
;WITH cte AS (
    SELECT 
     soh.* 
     ,sod.* 
     ,MIN(soh.OrderDate) OVER (PARTITION BY soh.CustomerId) as MinOrderDate 
    FROM 
     Sales.SalesOrderHeader soh 
     INNER JOIN Sales.SalesOrderDetail sod 
     ON soh.SalesOrderId = sod.SalesOrderId 
) 

SELECT * 
FROM 
    cte 
WHERE 
    OrderDate BETWEEN MinOrderDate AND DATEADD(year,1,MinOrderDate) 

我同意使用MIN(的VKP的方法)OVER但与他的日期比较。如果您希望包含日期或下面的代码以排除较高日期,我会使用BETWEEN。我不同意365比较的原因是闰年。

OrderDate >= MinOrderDate 
AND OrderDate < DATEADD(year,1,MinOrderDate) 
+0

只是一个小小的评论 - 'soh。*'和'sod。*'不起作用,您需要指定列名称。无论如何,非常感谢您的答案,这是我不知道的东西:) – katta

+0

@katta soh。*和sod。*,因为他们共享至少一个列名SalesOrderId它不会工作,但如果没有共同的列名它会工作的表之间。 – Matt

+0

好了解,谢谢! – katta

1

我认为这有点简单。

窗口函数为您提供每个客户的第一个订单日期。然后您只需为每位客户选择指定范围内的订单。

SELECT customerid,orderdate,productid 
FROM (
SELECT 
soh.*,sod.*, 
MIN(soh.OrderDate) OVER(PARTITION BY soh.CustomerID) AS FirstOrderDate 
FROM Sales.SalesOrderHeader soh 
JOIN Sales.SalesOrderDetail sod ON sod.SalesOrderID=soh.SalesOrderID 
) t 
WHERE DATEDIFF(dd,firstorderdate,orderdate) <= 365