2017-04-12 142 views
0

道歉,如果這是重複的 - 我已經搜索了一個答案,但我發現並不完全是我正在尋找。SQL Server - 從存儲過程模擬記錄

我有一個非常簡單的存儲過程,從庫存表返回基於日期的股票。這需要開始日期結束日期 PARAMS與配貨ID

查詢是像下面...

select 
    S.Date, 
    S.Amount 
from Stock S 
where 
    S.StockistID = @pi_stockistId and 
    S.Date >= @pi_startDate and 
    S.Date <= @pi_endDate 

我需要確保的是,總有一個行返回所要求的日期範圍 - 即使是在數據庫中沒有記錄日期和存貨。嘲笑的記錄將有一個零數量。

數據正在通過到外部系統供給,所以不需要插入記錄,除非所述系統增加了從零值(我有沒有必要在表存儲數以千計的空記錄)。

如果來自外部系統的後續調用量的增加,在這一點上,我將插入記錄表。

我知道我可能會創建一個臨時表變量並插入不存在的記錄插入到結果集做到這一點 - 我只是想知道,如果我可以在查詢中做任何事情來阻止其使用表變量。

再次,道歉,如果這已被問及。

我使用SQL Server 2014

感謝

這裏的數據從庫存表

------------------------------------ 
| Date  | StockistId | Amount | 
------------------------------------ 
| 12/04/2017 | 1   | 10  | 
| 14/04/2017 | 1   | 20  | 
------------------------------------ 

如果我跑我的查詢樣本日期12/04/2017 - 14/04/2017庫存者1,我得到以下...

----------------------- 
| Date  | Amount | 
----------------------- 
| 12/04/2017 | 10  | 
| 14/04/2017 | 20  | 
----------------------- 

由於現時13/04/2017

沒有記錄我想做什麼回報...

----------------------- 
| Date  | Amount | 
----------------------- 
| 12/04/2017 | 10  | 
| 13/04/2017 | 0  | 
| 14/04/2017 | 20  | 
----------------------- 

凡我查詢「嘲笑」了一個紀錄爲13/04/2017年

+1

看到使用ROWCOUNT此鏈接 - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=140165你希望 – Randy

+1

哪個日期,如果有沒有記錄? – McNets

+0

@McNets日期範圍內的日期,但沒有記錄。我需要嘲笑這些日期的記錄。 –

回答

3

如果你有一個日曆表這將成爲一個非常簡單的查詢。

SELECT c.Date, 
     Amount = ISNULL(s.Amount, 0) 
FROM dbo.Calendar AS c 
     LEFT JOIN Stock AS s 
      ON s.Date = c.Date 
      AND s.StockistID = @pi_stockistId 
WHERE c.Date >= @pi_startDate 
AND  c.Date <= @pi_endDate; 

如果您沒有日曆表,我會建議您創建一個,它們非常有用。如果您不能創建一個是相當容易生成一個在飛行:

首先只產生了一系列使用交叉連接和ROW_NUMBER()

WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)), 
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2), 
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2) 
SELECT ROW_NUMBER() OVER(ORDER BY N) - 1 
FROM N3; 

這將產生從0號數字 - 9999,它應該涵蓋你需要的任何日期範圍。

然後你可以沿着使用這個號碼與DATEADD得到天的範圍:

DECLARE @pi_startDate DATE = '20170101', 
     @pi_endDate DATE = '20170301'; 

WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)), 
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2), 
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2), 
Numbers (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) - 1 FROM N3) 

SELECT TOP (DATEDIFF(DAY, @pi_startDate, @pi_endDate) + 1) 
     Date = DATEADD(DAY, N, @pi_startDate) 
FROM Numbers; 

,讓你的日期。

然後你只需要左加入到你的股票,表中的最後一步

DECLARE @pi_startDate DATE = '20170101', 
     @pi_endDate DATE = '20170301'; 

WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)), 
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2), 
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2), 
Calendar (Date) AS 
( SELECT TOP (DATEDIFF(DAY, @pi_startDate, @pi_endDate) + 1) 
      DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY N) - 1, @pi_startDate) 
    FROM N2 
) 
SELECT c.Date, 
     Amount = ISNULL(s.Amount, 0) 
FROM Calendar AS c 
     LEFT JOIN Stock AS s 
      ON s.Date = c.Date 
      AND s.StockistID = @pi_stockistId; 

更多日曆表,並生成離不開循環系列可在3部分的文章中找到:

+0

奇妙的信息,我認爲這將完全符合我的需要,也可用於其他目的。謝謝! –

+0

只是爲了更新你 - 這一切都非常出色 - 再次感謝! –

1

雖然接受答案是完全正確的,但我只是想提供另一種方式來創建日期 - 使用遞歸CTE。也許有爭議,但我會說這很簡單。

DECLARE @startDate DATE = '20170401'; 
DECLARE @endDate DATE = '20170410'; 

WITH CTE_Dates AS 
(
    SELECT @StartDate AS Dt 
    UNION ALL 
    SELECT DATEADD(DAY,1,Dt) 
    FROM CTE_Dates 
    WHERE Dt < @endDate 
) 
SELECT * 
FROM CTE_Dates 
--LEFT JOIN to your data here 
OPTION (MAXRECURSION 0); -- needed if range is more than 100 days 
+0

如果你經常需要這個和不同的查詢,最好像GarethD說的 - 創建物理日曆表。運行這個(或另一個查詢)一次來填充(例如1900-2099)。把聚集索引放在它上面,並且你設置好。 –

+0

感謝您的建議 - 總是很高興有幾種不同的做法:-) –