如果没有找到特定日期的记录,则返回结果集中的行

时间:2015-04-15 10:07:50

标签: sql sql-server

我创建了一个返回以下输出的查询。

Date          Day      Sale Qty     Purchase Qty      Transfer Qty
------------------------------------------------------------------
05/04/2015    1           11             0                0
07/04/2015    3            0            16                0
08/04/2015    4           12            14               17
11/04/2015    7            1             2                0

我目前的查询如下。

(select T1.Date,T1.Day,T1.SaleQty,0 as PurchaseQty,0 as TransferQty from SaleTable T1)
union all
(select T2.Date,T2.Day,0 as SaleQty,T2.PurchaseQty,0 as TransferQty from PurchaseTable T2)
union all
(select T3.Date,T3.Day,0 as SaleQty,0 as PurchaseQty,T3.TransferQty from TransferTable T3)

所需输出采用以下格式

Date          Day      Sale Qty     Purchase Qty      Transfer Qty
------------------------------------------------------------------
05/04/2015    1           11             0                0
06/04/2015    2            0             0                0
07/04/2015    3            0            16                0
08/04/2015    4           12            14               17
09/04/2015    5            0             0                0
10/04/2015    6            0             0                0
11/04/2015    7            1             2                0

如果没有为该日期输出返回任何结果集,我应该如何编写查询以返回包含日期和日期的行。

2 个答案:

答案 0 :(得分:1)

您需要一个表作为查找表,查找缺少的日期和天数,以涵盖查询结果中的日期范围。你可以这样创建一个:

-- add a temp table for your sample data
CREATE TABLE #Results
    ([Date] datetime, [Day] int, [Sale Qty] int, [Purchase Qty] int, [Transfer Qty] int)
;
-- insert your sample data
INSERT INTO #Results
    ([Date], [Day], [Sale Qty], [Purchase Qty], [Transfer Qty])
VALUES
    ('2015-04-05 00:00:00', 1, 11, 0, 0),
    ('2015-04-07 00:00:00', 3, 0, 16, 0),
    ('2015-04-08 00:00:00', 4, 12, 14, 17),
    ('2015-04-11 00:00:00', 7, 1, 2, 0)
;
-- find the max date
DECLARE @MaxDate DATETIME = (SELECT TOP 1 [Date] FROM #Results ORDER BY [Date] DESC)
-- recursive cte to build the date & day lookup table
;WITH cte AS (
    -- cte anchor is the min date and day = 1
    SELECT MIN([Date]) AS DateValue, 1 AS [Day] 
    FROM #Results
    UNION ALL
    -- uses dateadd to increment days until @MaxDate reached
    SELECT DATEADD(DAY, 1, cte.DateValue), [Day] +1
    FROM cte
    WHERE DATEADD(DAY, 1, cte.DateValue) <= @MaxDate
)
-- inserts values into temp lookup table
SELECT * 
INTO #DateLookup
FROM cte

这将使用结果中包含这些值的最低和最高日期创建一个包含值范围的临时表:

DateValue                Day
----------------------------
2015-04-05 00:00:00.000  1
2015-04-06 00:00:00.000  2
2015-04-07 00:00:00.000  3
2015-04-08 00:00:00.000  4
2015-04-09 00:00:00.000  5
2015-04-10 00:00:00.000  6
2015-04-11 00:00:00.000  7

然后,您需要链接到此表并将所有NULL值替换为0,如下所示:

SELECT #DateLookup.[DateValue] AS [Date],
       #DateLookup.[Day] ,
       COALESCE([Sale Qty],0) AS [Sale Qty],
       COALESCE([Purchase Qty],0) AS [Purchase Qty],
       COALESCE([Transfer Qty],0) AS [Transfer Qty]
FROM #DateLookup
LEFT JOIN #Results ON #DateLookup.DateValue = #Results.[Date]

-- some tidy up
DROP TABLE #Results
DROP TABLE #DateLookup

答案 1 :(得分:0)

如果您的系统中没有日期表,请添加一个。你可以使用这个t-sql脚本:

CREATE TABLE TblDates(TheDate date not null);

DECLARE @StartDate date,
        @NumberOfDates int,
        @Counter int

SELECT @StartDate = GETDATE(), -- or whatever date you want
       @NumberOfDates = 100, -- or whatever number of dates you want after start date
       @Counter = 0;

WHILE(@Counter < @NumberOfDates)
BEGIN
    INSERT INTO TblDates(TheDate) VALUES (DATEADD(d, @Counter, @StartDate)
END

运行此脚本后,您应该有一个可供使用的日期表。 那么你所要做的就是:

SELECT TheDate, 
       DATEPART(D, TheDate) As Day, 
       ISNULL(T1.SaleQty, 0) As SaleQty, 
       ISNULL(T2.PurchaseQty, 0) As PurchaseQty,
       ISNULL(T3.TransferQty, 0) As TransferQty
FROM tblDates LEFT JOIN 
SaleTable T1 ON(TheDate = T1.Date) LEFT JOIN
PurchaseTable T2 ON(TheDate = T2.Date) LEFT JOIN
TransferTable T3 ON(TheDate = T3.Date) 

更新

现在我考虑一下,你可以使用数字表创建一个可以保存日期的cte(创建数字表非常简单,就像我为日期表编写的脚本一样)

With DatesCTE(TheDate) AS
  SELECT DATEADD(D, TheNumber, @startDate)
  FROM NumbersTable
  WHERE DATEADD(D, TheNumber, @StartDate) < @EndDate

更新2

作为对此答案的评论中提及的Selva TS,即使没有数字表,也可以使用递归cte生成日期cte,如下所示:

DECLARE @StartDate datetime, @EndDate datetime
SELECT @StartDate = DATEADD(YEAR, -1, GETDATE()),  @EndDate = GETDATE()

;WITH Calendar AS(
    SELECT @StartDate dateidx
    UNION ALL
    SELECT dateidx + 1
    FROM   Calendar
    WHERE dateidx + 1 < @EndDate
)