SQL服务器如何获取不包括周末和节假日的日期差异?
SQL Server How to get Date Difference excluding Weekends and Holidays?
我有这个 table:
tbl_Sales
----------------------------------------
|Item_Code|Sold|Date |
|---------+----+-----------------------|
|BBPen100 |30 |2017-04-17 00:00:00.000|
|BBPen100 |21 |2017-04-13 00:00:00.000|
|BBPen100 |13 |2017-04-12 00:00:00.000|
|XSHIRT80 |0 |2017-04-17 00:00:00.000|
|XSHIRT80 |24 |2017-04-14 00:00:00.000|
|XSHIRT80 |9 |2017-04-13 00:00:00.000|
|XSHIRT80 |5 |2017-04-12 00:00:00.000|
|YBSHADE7 |0 |2017-04-17 00:00:00.000|
|YBSHADE7 |6 |2017-04-15 00:00:00.000|
|YBSHADE7 |0 |2017-04-13 00:00:00.000|
|YBSHADE7 |11 |2017-04-12 00:00:00.000|
----------------------------------------
如何获取最近 2 个工作日的最后一个非零售出值?这意味着我需要排除周末和假期。
我有这个 table,其中包含假期。
tbl_Holiday
-------------------------
|Holiday_Date |
|-----------------------|
|2017-04-14 00:00:00.000|
|2017-05-01 00:00:00.000|
|2017-10-18 00:00:00.000|
|2017-12-25 00:00:00.000|
-------------------------
例如今天是 2017-04-18,输出应该是这样的:
---------------------
|Item_Code|Last_Sold|
|---------+---------|
|BBPen100 |30 |
|XSHIRT80 |9 |
|YBSHADE7 |0 |
---------------------
目标是获取最近 2 个工作日的最后售出值,因此从 2017-04-17 开始计数。
输出分析:
BBPen100-since it has value from last 1 working day (2017-04-17), that value will be retrieved.
XSHIRT80-Zero value from last 1 working day (2017-04-17)
-2017-04-16 & 2017-04-15 are weekends
-2017-04-14 is holiday
-So value from 2017-04-13 will be retrieved.
YBSHADE7-Zero value from last 1 working day (2017-04-17)
-2017-04-16 & 2017-04-15 are weekends
-2017-04-14 is holiday
-2017-04-13 has Zero value
-2017-04-12 is beyond Last 2 working days
-So value retrived should be Zero
目前,我有这个查询:
SELECT Item_Code, Sold AS 'Last_Sold'
FROM tbl_Sales
WHERE CONVERT(date, [DATE]) = CASE
WHEN CONVERT(date, [DATE]) = CONVERT(date, DATEADD(day, -1, GETDATE())) THEN CONVERT(date, DATEADD(day, -1, GETDATE()))
WHEN CONVERT(date, [DATE]) <> CONVERT(date, DATEADD(day, -1, GETDATE())) THEN CONVERT(date, DATEADD(day, -2, GETDATE()))
当然,这不符合要求。
请帮我解决这个问题。
重要提示:考虑周末的假期,如果我运行周末或假期的节目怎么办。
提前致谢。
WITH cte1 AS(
SELECT t.*
FROM tbl_Sales t
LEFT JOIN tbl_Holiday hd
ON t.Date = hd.Holiday_Date
WHERE hd.Holiday_Date IS NULL AND
DATENAME(WEEKDAY, t.Date) <> 'Saturday' AND
DATENAME(WEEKDAY, t.Date) <> 'Sunday'
),
WITH cte2 AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Item_Code ORDER BY Date DESC) rn
FROM cte1
)
SELECT *
FROM cte2
WHERE rn=1
你可以试试
示例数据
DECLARE @SampleData as TABLE (Item_Code varchar(10), Sold int, Date datetime)
Insert into @SampleData VALUES
('BBPen100', 30,'2017-04-17 00:00:00.000'),
('BBPen100', 21,'2017-04-13 00:00:00.000'),
('BBPen100', 13,'2017-04-12 00:00:00.000'),
('XSHIRT80', 0 ,'2017-04-17 00:00:00.000'),
('XSHIRT80', 24,'2017-04-14 00:00:00.000'),
('XSHIRT80', 9 ,'2017-04-13 00:00:00.000'),
('XSHIRT80', 5 ,'2017-04-12 00:00:00.000'),
('YBSHADE7', 0 ,'2017-04-17 00:00:00.000'),
('YBSHADE7', 6 ,'2017-04-15 00:00:00.000'),
('YBSHADE7', 0 ,'2017-04-13 00:00:00.000'),
('YBSHADE7', 11,'2017-04-12 00:00:00.000')
DECLARE @TblHoliday AS TABLE
(
Holiday_Date date
)
INSERT INTO @TblHoliday
VALUES
('2017-04-14 00:00:00.000'),
('2017-05-01 00:00:00.000'),
('2017-10-18 00:00:00.000'),
('2017-12-25 00:00:00.000')
DECLARE @CurrentDate datetime = '2017-04-18 00:00:00'
您可以在@CurrentDate
之前计算@2PreviousWorkingDays
-- 2 Previous Working Day with out Holiday
DECLARE @2PreviousWorkingDay date = CASE
WHEN datepart(dw,@CurrentDate) IN (2,3) THEN dateadd(day,-4, @CurrentDate) -- 2 previous working day before monday
WHEN datepart(dw,@CurrentDate) IN (1) THEN dateadd(day,-3, @CurrentDate) -- 2 previous working day before sunday
ELSE dateadd(day,-2, @CurrentDate) -- other day week
END
-- with holiday
SELECT @2PreviousWorkingDay = dateadd(day,0 - (SELECT count(1) FROM @TblHoliday th
WHERE th.Holiday_Date BETWEEN @2PreviousWorkingDay AND @CurrentDate
ANd datepart(dw,th.Holiday_Date) NOT IN (7,1) -- calculate only holiday that isn't weekend
)
, @2PreviousWorkingDay
你想要的结果:
;with temps AS
(
SELECT *, row_number() over(PARTITION BY sd.Item_Code ORDER BY sd.[Date] DESC) AS Rn
FROM @SampleData sd
WHERE sd.[Date] >= @2PreviousWorkingDay -- 2 working days
AND NOT EXISTS (SELECT 1 FROM @TblHoliday th WHERE th.Holiday_Date = Cast(sd.[Date] AS date)) -- not holiday
AND datepart(dw,sd.[Date]) NOT IN (7,1) -- not weekend
AND sd.Sold <> 0 -- not zero sold
)
SELECT sd.Item_Code, ISNULL(t.Sold,0) AS Sold FROM
(
SELECT DISTINCT sd.Item_Code FROM @SampleData sd
) sd
LEFT JOIN temps t ON t.Item_Code = sd.Item_Code AND t.Rn = 1
演示 link:Rextester
我有这个 table:
tbl_Sales
----------------------------------------
|Item_Code|Sold|Date |
|---------+----+-----------------------|
|BBPen100 |30 |2017-04-17 00:00:00.000|
|BBPen100 |21 |2017-04-13 00:00:00.000|
|BBPen100 |13 |2017-04-12 00:00:00.000|
|XSHIRT80 |0 |2017-04-17 00:00:00.000|
|XSHIRT80 |24 |2017-04-14 00:00:00.000|
|XSHIRT80 |9 |2017-04-13 00:00:00.000|
|XSHIRT80 |5 |2017-04-12 00:00:00.000|
|YBSHADE7 |0 |2017-04-17 00:00:00.000|
|YBSHADE7 |6 |2017-04-15 00:00:00.000|
|YBSHADE7 |0 |2017-04-13 00:00:00.000|
|YBSHADE7 |11 |2017-04-12 00:00:00.000|
----------------------------------------
如何获取最近 2 个工作日的最后一个非零售出值?这意味着我需要排除周末和假期。 我有这个 table,其中包含假期。
tbl_Holiday
-------------------------
|Holiday_Date |
|-----------------------|
|2017-04-14 00:00:00.000|
|2017-05-01 00:00:00.000|
|2017-10-18 00:00:00.000|
|2017-12-25 00:00:00.000|
-------------------------
例如今天是 2017-04-18,输出应该是这样的:
---------------------
|Item_Code|Last_Sold|
|---------+---------|
|BBPen100 |30 |
|XSHIRT80 |9 |
|YBSHADE7 |0 |
---------------------
目标是获取最近 2 个工作日的最后售出值,因此从 2017-04-17 开始计数。 输出分析:
BBPen100-since it has value from last 1 working day (2017-04-17), that value will be retrieved.
XSHIRT80-Zero value from last 1 working day (2017-04-17)
-2017-04-16 & 2017-04-15 are weekends
-2017-04-14 is holiday
-So value from 2017-04-13 will be retrieved.
YBSHADE7-Zero value from last 1 working day (2017-04-17)
-2017-04-16 & 2017-04-15 are weekends
-2017-04-14 is holiday
-2017-04-13 has Zero value
-2017-04-12 is beyond Last 2 working days
-So value retrived should be Zero
目前,我有这个查询:
SELECT Item_Code, Sold AS 'Last_Sold'
FROM tbl_Sales
WHERE CONVERT(date, [DATE]) = CASE
WHEN CONVERT(date, [DATE]) = CONVERT(date, DATEADD(day, -1, GETDATE())) THEN CONVERT(date, DATEADD(day, -1, GETDATE()))
WHEN CONVERT(date, [DATE]) <> CONVERT(date, DATEADD(day, -1, GETDATE())) THEN CONVERT(date, DATEADD(day, -2, GETDATE()))
当然,这不符合要求。
请帮我解决这个问题。
重要提示:考虑周末的假期,如果我运行周末或假期的节目怎么办。
提前致谢。
WITH cte1 AS(
SELECT t.*
FROM tbl_Sales t
LEFT JOIN tbl_Holiday hd
ON t.Date = hd.Holiday_Date
WHERE hd.Holiday_Date IS NULL AND
DATENAME(WEEKDAY, t.Date) <> 'Saturday' AND
DATENAME(WEEKDAY, t.Date) <> 'Sunday'
),
WITH cte2 AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Item_Code ORDER BY Date DESC) rn
FROM cte1
)
SELECT *
FROM cte2
WHERE rn=1
你可以试试
示例数据
DECLARE @SampleData as TABLE (Item_Code varchar(10), Sold int, Date datetime)
Insert into @SampleData VALUES
('BBPen100', 30,'2017-04-17 00:00:00.000'),
('BBPen100', 21,'2017-04-13 00:00:00.000'),
('BBPen100', 13,'2017-04-12 00:00:00.000'),
('XSHIRT80', 0 ,'2017-04-17 00:00:00.000'),
('XSHIRT80', 24,'2017-04-14 00:00:00.000'),
('XSHIRT80', 9 ,'2017-04-13 00:00:00.000'),
('XSHIRT80', 5 ,'2017-04-12 00:00:00.000'),
('YBSHADE7', 0 ,'2017-04-17 00:00:00.000'),
('YBSHADE7', 6 ,'2017-04-15 00:00:00.000'),
('YBSHADE7', 0 ,'2017-04-13 00:00:00.000'),
('YBSHADE7', 11,'2017-04-12 00:00:00.000')
DECLARE @TblHoliday AS TABLE
(
Holiday_Date date
)
INSERT INTO @TblHoliday
VALUES
('2017-04-14 00:00:00.000'),
('2017-05-01 00:00:00.000'),
('2017-10-18 00:00:00.000'),
('2017-12-25 00:00:00.000')
DECLARE @CurrentDate datetime = '2017-04-18 00:00:00'
您可以在@CurrentDate
之前计算@2PreviousWorkingDays-- 2 Previous Working Day with out Holiday
DECLARE @2PreviousWorkingDay date = CASE
WHEN datepart(dw,@CurrentDate) IN (2,3) THEN dateadd(day,-4, @CurrentDate) -- 2 previous working day before monday
WHEN datepart(dw,@CurrentDate) IN (1) THEN dateadd(day,-3, @CurrentDate) -- 2 previous working day before sunday
ELSE dateadd(day,-2, @CurrentDate) -- other day week
END
-- with holiday
SELECT @2PreviousWorkingDay = dateadd(day,0 - (SELECT count(1) FROM @TblHoliday th
WHERE th.Holiday_Date BETWEEN @2PreviousWorkingDay AND @CurrentDate
ANd datepart(dw,th.Holiday_Date) NOT IN (7,1) -- calculate only holiday that isn't weekend
)
, @2PreviousWorkingDay
你想要的结果:
;with temps AS
(
SELECT *, row_number() over(PARTITION BY sd.Item_Code ORDER BY sd.[Date] DESC) AS Rn
FROM @SampleData sd
WHERE sd.[Date] >= @2PreviousWorkingDay -- 2 working days
AND NOT EXISTS (SELECT 1 FROM @TblHoliday th WHERE th.Holiday_Date = Cast(sd.[Date] AS date)) -- not holiday
AND datepart(dw,sd.[Date]) NOT IN (7,1) -- not weekend
AND sd.Sold <> 0 -- not zero sold
)
SELECT sd.Item_Code, ISNULL(t.Sold,0) AS Sold FROM
(
SELECT DISTINCT sd.Item_Code FROM @SampleData sd
) sd
LEFT JOIN temps t ON t.Item_Code = sd.Item_Code AND t.Rn = 1
演示 link:Rextester