我正在尝试使用此查询语句来排除休息日和持续时间,我们将其称为特定月份日历中的假期。 这是我尝试过的:
select Weekday from Get_Calendar_Date(DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST('2021-01-01'
AS datetime))+2, 0) ,DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST('2021-01-01' AS datetime))+2, -1))
except (select dayId as dayId from days)
--select Date from holiday,Get_Calendar_Date(DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST('2021-01-01' AS datetime))+2, 0) ,DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST('2021-01-01' AS datetime))+2, -1)) where Date between startDate and endDate
这是Get_Calendar_Date
ALTER FUNCTION [dbo].[Get_Calendar_Date]
(
@StartDate DATETIME
, @EndDate DATETIME
)
RETURNS TABLE
AS
RETURN
(
SELECT Tbl_Obj.RNo
, DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate) AS [Date]
, DATEPART(quarter,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [Quarter]
, DATEPART(dayofyear,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [DayofYear]
, DATEPART(WEEK,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [WeekofYear]
, DATEPART(YEAR,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [Year]
, DATEPART(MONTH,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [Month]
, DATEPART(DAY,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [Day]
, DATEPART(weekday,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [Weekday]
, DATENAME(MONTH,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [MonthName]
, DATENAME(weekday,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)) AS [WeekdayName]
, (RIGHT( REPLICATE('0',(4)) +
CONVERT([VARCHAR],DATEPART(YEAR,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)),0)
,(4)
)+
RIGHT( REPLICATE('0',(2)) +
CONVERT([VARCHAR],DATEPART(MONTH,DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate)),0)
,(2)
)
) AS [Vintage]
FROM ( SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) AS [RNo]
FROM sys.all_objects WITH (NOLOCK)
) Tbl_Obj
WHERE DATEADD(DAY,Tbl_Obj.RNo-1,@StartDate) <= @EndDate
)
except
,但我得到的是这样的:并且预期的结果应该是这样的,因为我在本月有四个 Friday
(dayId=6),我需要使用 6 获取所有 dayId(代表休息日的所有月份的星期五):>
异常结果:
Weekday
6
6
6
6
没有Except
的执行结果
select Weekday from Get_Calendar_Date(DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST('2021-01-01'
AS datetime))+2, 0) ,DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST('2021-01-01' AS datetime))+2, -1))
答案 0 :(得分:1)
请瞄准未来的 minimal, reproducable example。
示例数据
(可能更小。)
create table set1
(
day int
);
insert into set1 (day) values (1),(2),(3),(1),(2),(3),(4); -- contains 2x 3
create table set2
(
day int
);
insert into set2 (day) values (1),(2),(1),(2),(4); -- removed 3's
问题再现
select set1.day
from set1
except
select set2.day
from set2;
结果
day
---
3
只有唯一值会保留在您希望所有出现的位置。
解决方案
与not exists
select set1.day
from set1
where not exists ( select 'x'
from set2
where set2.day = set1.day );
与left join
select set1.day
from set1
left join set2
on set2.day = set1.day
where set2.day is null;
结果
day
---
3
3
Fiddle 查看实际情况。
答案 1 :(得分:1)
您可以使用不存在
select Weekday from Get_Calendar_Date(DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST('2021-01-01'
AS datetime))+2, 0) ,DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST('2021-01-01' AS datetime))+2, -1))
where not exists (select 1 from days where dayid=weekday)
答案 2 :(得分:0)
首先,@Sander 的回答非常好,告诉您您需要了解 IMO。我想更深入地研究这个问题。 EXCEPT 是一个 SET Operator,就像 INTERSECT
和 UNION
一样(UNION ALL 是一个多集运算符 - 不同的主题)。除了 Itzik Ben-Gan 的 T-SQL Fundamentals 书籍之外,几乎没有关于集合运算符主题的文档。请注意这些已发布的示例:TSQLFundamentals20160601
Set Operators 返回一个 Set,根据定义,它是唯一的(不同的)。这就是为什么,在 Sander 的例子中,EXCEPT 返回一个不同的值,而 LEFT JOIN 和 NOT EXISTS 不返回一个不同的集合。 JOIN(INNER、OUTER 和 CROSS)是 表运算符,它们返回一个多重集,也就是“包”——一个非不同的集合。让我们比较 EXCEPT、NOT EXISTS 和 THE LEFT JOIN 的执行计划。
EXCEPT 和 NOT EXISTS 在执行计划中利用 Anti Semi Join 表运算符。反连接是你说“把这里不存在的所有东西都给我”。半连接是从左表(NOT EXISTS 语句之前的表)返回一个不同的集合。LEFT JOIN 使用传统的 JOIN 运算符。
使反半连接计划更好的是它们能够完成工作,同时从 set2 表中检索更少的行。 EXCEPT 解决方案,忽略“估计成本” - EXCEPT 计划是最有效的,因为它通过为 NOT EXIST 检索 20 行与 28 行为 LEFT JOIN 检索 42 行来完成工作。
接下来是 STATISTICS IO(读取次数):
--==== NOT EXISTS
Table 'set2'. Scan count 1, logical reads 7, physical reads 0...
Table 'set1'. Scan count 1, logical reads 1, physical reads 0...
--==== LEFT JOIN
Table 'set2'. Scan count 1, logical reads 7, physical reads 0...
Table 'set1'. Scan count 1, logical reads 1, physical reads 0...
--==== EXCEPT
Table 'set2'. Scan count 1, logical reads 4, physical reads 0...
Table 'set1'. Scan count 1, logical reads 1, physical reads 0...
在幕后,EXCEPT 解决方案正在生成 1/2 的 IO。集合运算符可以很强大。