T-SQL: CTE row_number over() 第一行的错误结果
T-SQL: CTE row_number over() wrong result for the first line
我有以下 Calendar
table 从 2014-01-01
开始。
CREATE TABLE [dbo].[TO_BDB_NOSSCE_ISO_CALENDAR](
[ID] [int] IDENTITY(1,1) NOT NULL,
[DATE] [date] NOT NULL,
[YEAR] AS (datepart(year,[DATE])) PERSISTED,
[SEMESTER] AS (case when datepart(month,[DATE])<(7) then '1' else '2' end) PERSISTED NOT NULL,
[TRIMESTER] AS (case when datepart(month,[DATE])<(4) then '1' else case when datepart(month,[DATE])<(7) then '2' else case when datepart(month,[DATE])<(10) then '3' else '4' end end end) PERSISTED NOT NULL,
[MONTH] AS (case when len(CONVERT([varchar](2),datepart(month,[DATE]),(0)))=(1) then '0'+CONVERT([varchar](2),datepart(month,[DATE]),(0)) else CONVERT([varchar](2),datepart(month,[DATE]),(0)) end) PERSISTED,
[WEEK] AS (case when len(CONVERT([varchar](2),datepart(iso_week,[DATE]),(0)))=(1) then '0'+CONVERT([varchar](2),datepart(iso_week,[DATE]),(0)) else CONVERT([varchar](2),datepart(iso_week,[DATE]),(0)) end),
[DAY] AS (case when len(CONVERT([varchar](2),datepart(day,[DATE]),(0)))=(1) then '0'+CONVERT([varchar](2),datepart(day,[DATE]),(0)) else CONVERT([varchar](2),datepart(day,[DATE]),(0)) end) PERSISTED,
[WEEKNUMBER] AS (datepart(iso_week,[DATE])),
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
我创建了一个存储过程并将 2014-01-01
添加到 2020-12-31
。
PROCEDURE [dbo].[sp_INSERT_CALENDAR_DAYS_INVERVAL]
@Increment CHAR(1),
@StartDate DATETIME,
@EndDate DATETIME
AS
BEGIN
WITH cteRange (DateRange) AS (
SELECT @StartDate
UNION ALL
SELECT
CASE
WHEN @Increment = 'd' THEN DATEADD(dd, 1, DateRange)
WHEN @Increment = 'w' THEN DATEADD(ww, 1, DateRange)
WHEN @Increment = 'm' THEN DATEADD(mm, 1, DateRange)
END
FROM cteRange
WHERE DateRange <=
CASE
WHEN @Increment = 'd' THEN DATEADD(dd, -1, @EndDate)
WHEN @Increment = 'w' THEN DATEADD(ww, -1, @EndDate)
WHEN @Increment = 'm' THEN DATEADD(mm, -1, @EndDate)
END)
INSERT INTO [TO_BDB].[dbo].[TO_BDB_NOSSCE_ISO_CALENDAR] ([DATE])
SELECT DateRange
FROM cteRange
然后,我想检索绝对周编号,遵循以下逻辑:当前周 - 1(上周),是零周 (0),我想回顾 12 周和回顾 6 周走向未来。
with absolute_weeks as (
select distinct YEAR, WEEK
from [TO_BDB].[dbo].[TO_BDB_NOSSCE_ISO_CALENDAR]
where DATEADD(week, 0, DATE) between cast(DATEADD(WEEK, -12, GETDATE()) as date)
and cast(DATEADD(WEEK, +6, GETDATE()) as date)
)
select *, (row_number() over (order by YEAR, WEEK) - 13) as relative_week
from absolute_weeks
order by YEAR, WEEK;
我得到以下结果,-11 到 +6 周是正确的,但出于某种原因,-12 周不正确。你能解释为什么以及如何修复吗?:
YEAR WEEK relative_week
----------------------
2014 01 -12
2014 43 -11
2014 44 -10
2014 45 -9
2014 46 -8
2014 47 -7
2014 48 -6
2014 49 -5
2014 50 -4
2014 51 -3
2014 52 -2
2015 01 -1
2015 02 0
2015 03 1
2015 04 2
2015 05 3
2015 06 4
2015 07 5
2015 08 6
我认为问题在于e。 g.
DATEPART(ISO_WEEK, '20141231');
实际上 returns 1
- 这是正确的,但会弄乱您的数据。
您可以在基础 table 中为 ISO_Week 的年份使用单独的字段,如下所示:
ISOWEEKYEAR = YEAR(d) + CASE WHEN DATEPART(ISO_WEEK, d) = 1 AND MONTH(d) = 12 THEN 1 ELSE 0 END
正如@KekuSemau 指出的那样,问题与 2014 年 12 月 31 日的 ISOWEEK 为 1 有关。您可以通过在 DATE 或 YEAR,WEEK 订购来解决这个问题;
select year,week,(row_number() over (order by min([DATE])) - 13) as relative_week
from [dbo].[TO_BDB_NOSSCE_ISO_CALENDAR]
where [DATE] between DATEADD(WEEK, -12, GETDATE()) and DATEADD(WEEK, +6, GETDATE())
group by year,week
order by min([DATE])
当 'today' 处于一周的开始和结束时,您可能需要对此进行测试,以确保该行为符合您的目的。
顺便说一句 - 将问题正确组合、工作代码、清晰问题等的荣誉 - 似乎没有很多这样的:)
编辑1
这是一种完全不同的方法(我认为 :)
;with cteNumbers as (select top 20 row_number() over (order by object_id) -13 as rn from sys.objects)
select c.year,c.week,n.rn
from cteNumbers n
join [dbo].[TO_BDB_NOSSCE_ISO_CALENDAR] c on c.date = cast(dateadd(d, n.rn*7, getdate()) as date)
您仍然需要对此进行测试,以确保它在一周的开始和结束时 运行 达到您想要的效果。
希望对您有所帮助,
里斯
我有以下 Calendar
table 从 2014-01-01
开始。
CREATE TABLE [dbo].[TO_BDB_NOSSCE_ISO_CALENDAR](
[ID] [int] IDENTITY(1,1) NOT NULL,
[DATE] [date] NOT NULL,
[YEAR] AS (datepart(year,[DATE])) PERSISTED,
[SEMESTER] AS (case when datepart(month,[DATE])<(7) then '1' else '2' end) PERSISTED NOT NULL,
[TRIMESTER] AS (case when datepart(month,[DATE])<(4) then '1' else case when datepart(month,[DATE])<(7) then '2' else case when datepart(month,[DATE])<(10) then '3' else '4' end end end) PERSISTED NOT NULL,
[MONTH] AS (case when len(CONVERT([varchar](2),datepart(month,[DATE]),(0)))=(1) then '0'+CONVERT([varchar](2),datepart(month,[DATE]),(0)) else CONVERT([varchar](2),datepart(month,[DATE]),(0)) end) PERSISTED,
[WEEK] AS (case when len(CONVERT([varchar](2),datepart(iso_week,[DATE]),(0)))=(1) then '0'+CONVERT([varchar](2),datepart(iso_week,[DATE]),(0)) else CONVERT([varchar](2),datepart(iso_week,[DATE]),(0)) end),
[DAY] AS (case when len(CONVERT([varchar](2),datepart(day,[DATE]),(0)))=(1) then '0'+CONVERT([varchar](2),datepart(day,[DATE]),(0)) else CONVERT([varchar](2),datepart(day,[DATE]),(0)) end) PERSISTED,
[WEEKNUMBER] AS (datepart(iso_week,[DATE])),
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
我创建了一个存储过程并将 2014-01-01
添加到 2020-12-31
。
PROCEDURE [dbo].[sp_INSERT_CALENDAR_DAYS_INVERVAL]
@Increment CHAR(1),
@StartDate DATETIME,
@EndDate DATETIME
AS
BEGIN
WITH cteRange (DateRange) AS (
SELECT @StartDate
UNION ALL
SELECT
CASE
WHEN @Increment = 'd' THEN DATEADD(dd, 1, DateRange)
WHEN @Increment = 'w' THEN DATEADD(ww, 1, DateRange)
WHEN @Increment = 'm' THEN DATEADD(mm, 1, DateRange)
END
FROM cteRange
WHERE DateRange <=
CASE
WHEN @Increment = 'd' THEN DATEADD(dd, -1, @EndDate)
WHEN @Increment = 'w' THEN DATEADD(ww, -1, @EndDate)
WHEN @Increment = 'm' THEN DATEADD(mm, -1, @EndDate)
END)
INSERT INTO [TO_BDB].[dbo].[TO_BDB_NOSSCE_ISO_CALENDAR] ([DATE])
SELECT DateRange
FROM cteRange
然后,我想检索绝对周编号,遵循以下逻辑:当前周 - 1(上周),是零周 (0),我想回顾 12 周和回顾 6 周走向未来。
with absolute_weeks as (
select distinct YEAR, WEEK
from [TO_BDB].[dbo].[TO_BDB_NOSSCE_ISO_CALENDAR]
where DATEADD(week, 0, DATE) between cast(DATEADD(WEEK, -12, GETDATE()) as date)
and cast(DATEADD(WEEK, +6, GETDATE()) as date)
)
select *, (row_number() over (order by YEAR, WEEK) - 13) as relative_week
from absolute_weeks
order by YEAR, WEEK;
我得到以下结果,-11 到 +6 周是正确的,但出于某种原因,-12 周不正确。你能解释为什么以及如何修复吗?:
YEAR WEEK relative_week
----------------------
2014 01 -12
2014 43 -11
2014 44 -10
2014 45 -9
2014 46 -8
2014 47 -7
2014 48 -6
2014 49 -5
2014 50 -4
2014 51 -3
2014 52 -2
2015 01 -1
2015 02 0
2015 03 1
2015 04 2
2015 05 3
2015 06 4
2015 07 5
2015 08 6
我认为问题在于e。 g.
DATEPART(ISO_WEEK, '20141231');
实际上 returns 1
- 这是正确的,但会弄乱您的数据。
您可以在基础 table 中为 ISO_Week 的年份使用单独的字段,如下所示:
ISOWEEKYEAR = YEAR(d) + CASE WHEN DATEPART(ISO_WEEK, d) = 1 AND MONTH(d) = 12 THEN 1 ELSE 0 END
正如@KekuSemau 指出的那样,问题与 2014 年 12 月 31 日的 ISOWEEK 为 1 有关。您可以通过在 DATE 或 YEAR,WEEK 订购来解决这个问题;
select year,week,(row_number() over (order by min([DATE])) - 13) as relative_week
from [dbo].[TO_BDB_NOSSCE_ISO_CALENDAR]
where [DATE] between DATEADD(WEEK, -12, GETDATE()) and DATEADD(WEEK, +6, GETDATE())
group by year,week
order by min([DATE])
当 'today' 处于一周的开始和结束时,您可能需要对此进行测试,以确保该行为符合您的目的。
顺便说一句 - 将问题正确组合、工作代码、清晰问题等的荣誉 - 似乎没有很多这样的:)
编辑1
这是一种完全不同的方法(我认为 :)
;with cteNumbers as (select top 20 row_number() over (order by object_id) -13 as rn from sys.objects)
select c.year,c.week,n.rn
from cteNumbers n
join [dbo].[TO_BDB_NOSSCE_ISO_CALENDAR] c on c.date = cast(dateadd(d, n.rn*7, getdate()) as date)
您仍然需要对此进行测试,以确保它在一周的开始和结束时 运行 达到您想要的效果。
希望对您有所帮助,
里斯