2

Thought about creating a bit of a calendar with recursive CTE on dates. However I get the following error once running it:

Types don't match between the anchor and the recursive part in column "ddmmyyyy" of recursive query "cte_days"

Code:

WITH cte_days(n, weekd, ddmmyyyy) AS
(   
    SELECT 
        0, DATENAME(DW, '09-03-1983'), CONVERT(varchar, '09-03-1983', 10)
    UNION ALL   
    SELECT 
        0 + 1, DATENAME(weekday, DATEADD(day, 1, '09-03-1983')), DATEADD(day, 1, '09-03-1983')                      
    FROM 
        cte_days
    WHERE 
        n < 10
)   
SELECT * 
FROM cte_days

At that I tried testing data in ddmmyyyy column running two SELECTS in the middle and it was returned accurate:

0   Saturday    1983-09-03 00:00:00.000
1   Sunday      1983-09-04 00:00:00.000 

It also worked fine once creating a temp table with date column and sticking both values in there...

So can you help finding a mismatch?

Thank you.

1
  • Tip: You can use SQL_Variant_Property to display the data type of an expression. Compare SELECT SQL_Variant_Property( 0, 'BaseType' ), SQL_Variant_Property( DATENAME(DW, '09-03-1983'), 'BaseType' ), SQL_Variant_Property( CONVERT(varchar, '09-03-1983', 10), 'BaseType' ) and SELECT SQL_Variant_Property( 0 + 1, 'BaseType' ), SQL_Variant_Property( DATENAME(weekday, DATEADD(day, 1, '09-03-1983')), 'BaseType' ), SQL_Variant_Property( DATEADD(day, 1, '09-03-1983') , 'BaseType' );. Commented Dec 13, 2019 at 3:50

4 Answers 4

3

SQL Server is picky about types of strings. But I would recommend focusing on dates in the CTE and doing your conversions afterwards:

WITH cte_days(n, dte) AS (
      SELECT 0, CONVERT(date, '19830309')
      UNION ALL
      SELECT n+1, DATEADD(day, 1, dte)
      FROM cte_days
      WHERE n < 10
     )
SELECT n, DATENAME(weekday, dte), CONVERT(VARCHAR(255), dte, 10)
FROM cte_days;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you Gordon, you are very helpful as usual.
3

"Thought about creating a bit of a calendar with recursive CTE on dates." Honestly, I recommend a Tally over an rCTE. An rCTE is actually significantly slower than a Tally. This should be more than enough to get you started:

DECLARE @StartDate date = '19830309';

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (100) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
    FROM N N1, N N2, N N3) --Add more Cartisian Joins and increase value of TOP to get more rows
SELECT I,
       DATENAME(WEEKDAY,DATEADD(DAY, I, @StartDate)) AS DayName,
       DATEADD(DAY, I, @StartDate) AS DyDate
FROM Tally;

1 Comment

That's a beauty. Thank you Larnu!
0

Using CAST function instead of CONVERT also helps:

WITH cte_days(n, weekd, ddmmyyyy) 
AS (    
 SELECT 0, DATENAME(DW, '09-03-1983'),CAST(CAST('09-03-1983' AS DATE) AS DATETIME)       
        UNION ALL   
 SELECT n+1, DATENAME(weekday, DATEADD(day, 1, '09-03-1983')), DATEADD(day, 1, '09-03-1983')                        
 FROM cte_days                                                                  
    WHERE n < 10                                                                        
)   
SELECT * FROM cte_days 

1 Comment

Yeah, and it always says Sunday starting from line 2 :)
0

Moving your "FROM cte_days WHERE n < 10" outside of your CTE will work.

    --Your Code: 
WITH cte_days(n, weekd, ddmmyyyy) AS
(   
    SELECT 
        0, DATENAME(DW, '09-03-1983'), CONVERT(varchar, '09-03-1983', 10)
    UNION ALL   
    SELECT 
        0 + 1, DATENAME(weekday, DATEADD(day, 1, '09-03-1983')), DATEADD(day, 1, '09-03-1983')                      
    FROM 
        cte_days
    WHERE 
        n < 10
)   
SELECT * 
FROM cte_days

Working Code:

    WITH cte_days(n, weekd, ddmmyyyy) AS
(   
    SELECT 
        0, DATENAME(DW, '09-03-1983'), CONVERT(varchar, '09-03-1983', 10)
    UNION ALL   
    SELECT 
        0 + 1, DATENAME(weekday, DATEADD(day, 1, '09-03-1983')), DATEADD(day, 1, '09-03-1983')                      
)   
SELECT * 
FROM cte_days
    WHERE 
        n < 10

Above returns the following results:

n   weekd   ddmmyyyy
0   Saturday    1983-09-03 00:00:00.000
1   Sunday  1983-09-04 00:00:00.000

1 Comment

Yes, but the idea with that 10 was to make it iterate 10 times so I would get 10 days from the anchor date. With the suggested code I get 2.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.