4

我有两张桌子。

包含客户和日期的订单表。来自数据仓库的日期维度表。

订单表不包含给定月份中每个日期的活动,但我需要返回一个结果集,以填补日期和客户的空白。

例如,我需要这个:

客户日期
================================
客户 1 2012 年 1 月 15 日   
客户 1 2012 年 1 月 18 日
Cust2 2012 年 1 月 5 日
客户 2 2012 年 1 月 8 日

看起来像这样:

客户日期
==============================
客户 1 2012 年 1 月 15 日   
客户 1 2012 年 1 月 16 日   
客户 1 2012 年 1 月 17 日       
客户 1 2012 年 1 月 18 日
Cust2 2012 年 1 月 5 日
客户 2 2012 年 1 月 6 日
客户 2 2012 年 1 月 7 日
客户 2 2012 年 1 月 8 日

这似乎是一个左外连接,但它没有返回预期的结果。这是我正在使用的,但这并没有按预期返回日期表中的每个日期。

SELECT o.customer, 
       d.fulldate
FROM   datetable d 
       LEFT OUTER JOIN orders o 
                    ON d.fulldate = o.orderdate 
WHERE  d.calendaryear IN ( 2012 ); 
4

4 回答 4

6

问题是您需要所有日期的所有客户。当您执行时left outer join,您将获得客户字段的 NULL。

下面通过cross join输入客户姓名和日期来设置驱动程序表:

SELECT driver.customer, driver.fulldate, o.amount 
FROM   (select d.fulldate, customer
        from datetable d cross join
             (select customer
              from orders
              where year(orderdate) in (2012)
             ) o
        where d.calendaryear IN ( 2012 )
       ) driver LEFT OUTER JOIN
       orders o 
       ON driver.fulldate = o.orderdate and
          driver.customer = o.customer;

请注意,此版本假定calendaryearyear(orderdate).

于 2013-07-03T14:58:42.967 回答
6

您可以使用递归 CTE 来获取两个日期之间的所有日期,而无需datetable

;WITH CTE_MinMax AS
(
    SELECT Customer, MIN(DATE) AS MinDate, MAX(DATE) AS MaxDate
    FROM dbo.orders
    GROUP BY Customer
)
,CTE_Dates AS
(
    SELECT Customer, MinDate AS Date
    FROM CTE_MinMax
    UNION ALL
    SELECT c.Customer, DATEADD(DD,1,Date) FROM CTE_Dates c
    INNER JOIN CTE_MinMax mm ON c.Customer = mm.Customer
    WHERE DATEADD(DD,1,Date) <= mm.MaxDate
)
SELECT c.* , COALESCE(o.Amount, 0)
FROM CTE_Dates c
LEFT JOIN Orders o ON c.Customer = o.Customer AND c.Date = o.Date
ORDER BY Customer, Date
OPTION (MAXRECURSION 0)

SQLFiddle 演示

于 2013-07-03T15:04:23.423 回答
1

假设 datetable 包括一年中的每个日期,您可以使用一个简单的 CTE

WITH OrdersCustomerDateBorders AS
(
    SELECT CustomerID, MIN(fulldate) AS FirstOrderDate, MAX(fulldate) AS LastOrderDate
    FROM orders
    GROUP BY customer
)
select o.customer, d.fulldate, ISNULL(o.amount, 0) AS Amount
from orders o
INNER JOIN OrdersCustomerDateBorders OCDB ON OCDB.CustomerID = o.CustomerID
INNER JOIN datetable d ON  ON d.fulldate between OCDB.FirstOrderDate AND OCDB.LastOrderDate
WHERE d.calendaryear in (2012);
于 2013-07-03T15:39:45.790 回答
1

这是一个简单的方法:

SELECT  A.Customer,
        B.fulldate [Date],
        ISNULL(C.Amount,0) Amount
FROM (  SELECT  Customer, 
                MIN([Date]) MinDate,
                MAX([Date]) MaxDate
        FROM Orders
        GROUP BY Customer) A
LEFT JOIN DateTable B
    ON B.fulldate BETWEEN A.MinDate AND A.MaxDate
LEFT JOIN Orders C
    ON A.Customer = C.Customer 
    AND B.fulldate = C.[Date]
于 2013-07-03T15:13:40.683 回答