I get the following error when I try to execute a particular recursive CTE:
Msg 240, Level 16, State 1, Line 8
Types don't match between the anchor and the recursive part in column "data_list" of recursive query "CTE".
This is nonsense. Each field is explicitly cast to VARCHAR(MAX)
.
Please help me. I've read many answers to this problem, here and elsewhere, all of which advise explicitly casting the column in question. I'm already doing this, and still get the error.
This code will reproduce the error:
if object_id('tempdb..#tOwner') IS NOT NULL drop table #tOwner;
CREATE TABLE #tOwner(id int identity(1,1), email varchar(max) );
insert into #towner values ( cast('[email protected]' as varchar(max)));
insert into #towner values ( cast('tsql rage' as varchar(max)));
insert into #towner values ( cast('[email protected]' as varchar(max)));
insert into #towner values ( cast('einstein.x.m' as varchar(max)));
;WITH data AS (
SELECT DISTINCT convert(varchar(max), email) datapoint FROM #tOwner
), CTE ( data_list, datapoint, length ) AS (
SELECT convert(VARCHAR(max), '' ),convert(VARCHAR(max), '' ), 0
UNION ALL
SELECT convert(VARCHAR(max),d.datapoint+';'+data_list),convert(VARCHAR(max),d.datapoint), length + 1
FROM CTE c CROSS JOIN data d WHERE d.datapoint > c.datapoint
)
SELECT D.data_list
FROM (
SELECT data_list, RANK() OVER ( PARTITION BY 1 ORDER BY length DESC )
FROM CTE
) D ( data_list, rank )
WHERE rank = 1 ;
drop table #tOwner;
If you find it relevant, SELECT left(@@VERSION, 70)
returns:
Microsoft SQL Server 2005 - 9.00.4053.00 (X64) May 26 2009 14:13:01
A CTE can be recursive or non-recursive. A recursive CTE is a CTE that references itself. A recursive CTE can join a table to itself as many times as necessary to process hierarchical data in the table. CTEs increase modularity and simplify maintenance.
Recursive CTE Syntax A recursive CTE references itself. It returns the result subset, then it repeatedly (recursively) references itself, and stops when it returns all the results. FROM cte_name; Again, at the beginning of your CTE is the WITH clause.
A recursive CTE is a subquery which refer to itself using its own name. The recursive CTEs are defined using WITH RECURSIVE clause. There should be a terminating condition to recursive CTE. The recursive CTEs are used for series generation and traversal of hierarchical or tree-structured data.
A Recursive CTE is a CTE that references itself. The CTE repeatedly executes, returns subsets of data, until it returns the complete result set. Syntax. WITH cte_name AS ( cte_query_definition (or) initial query -- Anchor member UNION ALL recursive_query with condition -- Recursive member ) SELECT * FROM cte_name. SQL.
Will A's comment on my original post found the key - the collation. My posted query worked for me in the master database, too.
Examining the collation suggested I was on the right track.
SELECT DATABASEPROPERTYEX('crm_mscrm', 'Collation') crmSQLCollation
crmSQLCollation
--------------------
Latin1_General_CI_AI
(1 row(s) affected)
SELECT DATABASEPROPERTYEX('master', 'Collation') masterSQLCollation
masterSQLCollation
----------------------------
SQL_Latin1_General_CP1_CI_AS
(1 row(s) affected)
Some frenzied searching later, I had this monstrosity of code, which
To wit:
if object_id('tempdb..#tOwner') IS NOT NULL drop table #tOwner;
CREATE TABLE #tOwner(id int identity(1,1), email nvarchar(max) );
insert into #towner values ( cast('[email protected]' as nvarchar(max)));
insert into #towner values ( cast('tsql rage' as nvarchar(max)));
insert into #towner values ( cast('[email protected]' as nvarchar(max)));
insert into #towner values ( cast('einstein.x.m' as nvarchar(max)));
;WITH data AS (
SELECT DISTINCT convert(nvarchar(max), email) datapoint FROM #tOwner
), CTE ( data_list, datapoint, length ) AS (
SELECT convert(nvarchar(max), '' ) Collate SQL_Latin1_General_CP1_CI_AS,convert(nvarchar(max), '' ) Collate SQL_Latin1_General_CP1_CI_AS, 0
UNION ALL
SELECT convert(nvarchar(max),d.datapoint+';'+data_list) Collate SQL_Latin1_General_CP1_CI_AS,convert(nvarchar(max),d.datapoint) Collate SQL_Latin1_General_CP1_CI_AS, length + 1
FROM CTE c CROSS JOIN data d WHERE d.datapoint > c.datapoint
)
SELECT D.data_list
FROM (
SELECT data_list, RANK() OVER ( PARTITION BY 1 ORDER BY length DESC )
FROM CTE
) D ( data_list, rank )
WHERE rank = 1 ;
if object_id('tempdb..#tOwner') IS NOT NULL drop table #tOwner;
Sitting beautifully in my results window is the expected:
data_list
------------------------------------------------
tsql rage;einstein.x.m;[email protected];[email protected];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With