Fill In The Date Gaps With Date Table

前端 未结 4 1995
甜味超标
甜味超标 2020-12-21 04:47

I have two tables.

An orders table with customer, and date. A date dimension table from a data warehouse.

The orders table does not contain activity for ev

相关标签:
4条回答
  • 2020-12-21 05:10

    Here is a simple way to do it:

    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]
    
    0 讨论(0)
  • 2020-12-21 05:14

    Assuming that datetable includes every date of the year you can do with one simple 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);
    
    0 讨论(0)
  • 2020-12-21 05:20

    The problem is that you need all customers for all dates. When you do the left outer join, you are getting NULL for the customer field.

    The following sets up a driver table by cross joining the customer names and dates:

    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;
    

    Note that this version assumes that calendaryear is the same as year(orderdate).

    0 讨论(0)
  • 2020-12-21 05:31

    You can use recursive CTE to get all dates between two dates without need for 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 DEMO

    0 讨论(0)
提交回复
热议问题