这完全是我对CTE缺乏完全了解 - 只是刚开始使用它们。我有以下数据:
create table tblHolidays
(
HolidayId int identity(101, 1) Primary Key, HolidayDate datetime
)
go
insert into tblHolidays values
('2015-01-10'), ('2015-01-09'), ('2015-01-08'), ('2015-01-07'),
('2015-02-19'), ('2015-03-11'), ('2015-04-11')
go
和以下代码(尝试检索非假日的前一天):
with CTE1 as
(
select *,
dateadd(dd, -1, HolidayDate) as PrevDay,
row_number() over(order by HolidayDate desc) as RN
from tblHolidays
),
CTE2 as
(
select *,
case
when PrevDay = lead(HolidayDate) over(order by (select null))
then 0 else 1
--when PrevDay = lead(HolidayDate) over(order by HolidayDate desc) then 0 else 1
end as Foo
from CTE1 as C
)
select top 1 PrevDay, HolidayDate from CTE2 where PrevDay < cast('2015-01-10' as datetime) and Foo = 1
执行时,我收到各种结果,我不知道为什么。我期望的输出是:
PrevDay HolidayDate
2015-01-06 2015-01-07
AND,它是最初插入的上面的结果集。但是,如果我将另一条记录添加到tblHolidays并将2015-01-06设置为假日,从而想要检索2015-01-05的前一天,我没有得到它,我仍然得到上述结果。
但是,如果我将RND列替换为RN,我会得到正确的结果!我不明白这个。我知道还有其他方法可以做到这一点,但我真的想要理解为什么它的行为方式如此。我认为CTE的执行顺序基本上缺少一些东西。
答案 0 :(得分:0)
让我建议另一种方法。
而不是设置一个假期日使用期限。接下来,udf内联函数模拟句点表:
-- holidays periods
create function dbo.getHolidays()
returns table
as
return
(
with rst as
(
select HolidayDate,
iif(lag(HolidayDate) over (order by HolidayDate) = dateadd(dd, -1, HolidayDate), null, 1) reset
from tblHolidays
), g as
(
select HolidayDate,
count(reset) over (order by HolidayDate) as grp
from rst
)
select min(HolidayDate) as StartDate, max(HolidayDate) as EndDate
from g
group by grp
);
它返回:
select * from dbo.getHolidays();
GO
StartDate | EndDate
:------------------ | :------------------
06/01/2015 00:00:00 | 10/01/2015 00:00:00
19/02/2015 00:00:00 | 19/02/2015 00:00:00
11/03/2015 00:00:00 | 11/03/2015 00:00:00
11/04/2015 00:00:00 | 11/04/2015 00:00:00
现在,您可以通过这种方式轻松检查某个日期是否属于某个假期:
declare @dateSearch datetime;
set @dateSearch = '20150110'
select *
from dbo.getHolidays()
where @dateSearch >= startDate
and @dateSearch <= endDate;
GO
StartDate | EndDate
:------------------ | :------------------
06/01/2015 00:00:00 | 10/01/2015 00:00:00
dbfiddle here
答案 1 :(得分:0)
错误出现在这段代码中:lead(HolidayDate) over(order by (select null))
。
使用窗口函数时,如果在任何子句中指定select null
,查询可能会随机运行 - 每次运行时会产生不同的结果 - 这就是您现在面临的问题。
order by (select null)
- 顺序是表的物理顺序,每次运行此类查询时都可以获得不同的结果。
partition by (select null)
- 没有分区。它比制定order by (select null)
条款(明确 - 它根本没有危险)更危险,因为这种查询的结果不会是随机的。
您必须指定正确的order by
子句,如下所示:
lead(HolidayDate) over(order by HolidayDate)
。这将根据您的需要提供输出。