Reputation: 25
I know this has been asked before but I have checked the existing solutions and I can't find the issue. For example there are no dates before 2000-01-01 or after 2019-12-24. In addition all dates are in YYYY-MM-DD to remove ambiguity.
The code below runs fine, but when I remove the comments on the second to last line (for the criteria) I get the error:
"Cannot construct data type date, some of the arguments have values which are not valid."
. This suggests that the problem is with either StartDate or EndDate but I cannot see an issue.
I would really appreciate someone helping me to get past this blocker.
(The code is completely self contained using derived tables).
Thanks in advance
Declare @StartDate AS datetime;
Declare @EndDate AS datetime;
Set @StartDate = '2017/06/01';
Set @EndDate = '2018/05/01';
WITH theIntegers AS
(SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n AS theInteger
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) hundreds(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) thousands(n)
WHERE ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n >0),
theWeeks AS
(SELECT theInteger AS Wk FROM theIntegers
WHERE theInteger > 0 AND theInteger < 53),
theYears AS
(SELECT theInteger AS Yr FROM theIntegers
WHERE theInteger > 2000 AND theInteger < 2020),
theDates AS
(SELECT Wk,Yr, DATEADD(WEEK,Wk-1,DATEFROMPARTS(Yr,1,1)) AS STDT
FROM theWeeks, theYears)
SELECT * FROM theDates
--WHERE StDt BETWEEN @StartDate AND @EndDate
ORDER BY StDt DESC
Upvotes: 1
Views: 1461
Reputation: 138960
SQL Server combines the where clauses from all parts of your query to one place in the execution plan, the left most Nested Loops Join operator.
The predicate looks like this from an estimated query plan.
dateadd(week,
[Union1010]+(10)*[Union1021]+(100)*[Union1032]+(1000)*[Union1043]-(1),
datefromparts([Union1055]+(10)*[Union1066]+(100)*[Union1077]+(1000)*[Union1088],
(1),
(1)))>= [@StartDate] AND
dateadd(week,
[Union1010]+(10)*[Union1021]+(100)*[Union1032]+(1000)*[Union1043]-(1),
datefromparts([Union1055]+(10)*[Union1066]+(100)*[Union1077]+(1000)*[Union1088],
(1),
(1)))<=[@EndDate] AND
([Union1055]+(10)*[Union1066]+(100)*[Union1077]+(1000)*[Union1088])>(2000) AND
([Union1055]+(10)*[Union1066]+(100)*[Union1077]+(1000)*[Union1088])<(2020) AND
([Union1055]+(10)*[Union1066]+(100)*[Union1077]+(1000)*[Union1088])>(0)
So SQL Server is trying to create date values for all rows coming out of theIntegers
before filtering out the rows on year and week and that makes your query trying to create dates with week numbers larger than 52.
You can fix your query by using top(52)
in theWeeks
CTE.
theWeeks AS
(SELECT TOP(52) theInteger AS Wk FROM theIntegers order by theInteger),
Upvotes: 1
Reputation: 16575
I can't explain it, but I have got it to work... I assume it's a one-off and do with optimization.
I've spun out the date creation to a function...
CREATE FUNCTION createDate(@wk int, @yr int)
RETURNS datetime
AS
begin
declare @dt datetime
set @dt = (select DATEADD(WEEK,@wk-1,DATEFROMPARTS(@yr,1,1)))
return @dt
end;
Then changed the query
Declare @StartDate AS datetime;
Declare @EndDate AS datetime;
Set @StartDate = '2017/06/01';
Set @EndDate = '2018/05/01';
WITH theIntegers AS
(SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n AS theInteger
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) hundreds(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) thousands(n)
WHERE ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n >0)
,theWeeks AS
(SELECT theInteger AS Wk FROM theIntegers
WHERE theInteger > 0 AND theInteger < 53),
theYears AS
(SELECT theInteger AS Yr FROM theIntegers
WHERE theInteger > 2000 AND theInteger < 2020)
,theDates AS
(SELECT Wk,Yr, dbo.createDate(wk,yr) AS STDT
FROM theWeeks, theYears)
SELECT * FROM theDates WHERE StDt BETWEEN @StartDate AND @EndDate ORDER BY StDt DESC;
Upvotes: 0