2010-08-06 8 views
9

je reçois l'erreur suivante lorsque je tente d'exécuter un CTE récursive particulier:T-SQL CTE Erreur: les types ne correspondent pas entre l'ancre et la partie récursive

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". 

Cela n'a aucun sens. Chaque champ est explicitement converti en VARCHAR(MAX). S'il vous plaît aidez-moi. J'ai lu beaucoup de réponses à ce problème, ici et ailleurs, qui conseillent explicitement de lancer la colonne en question. Je fais déjà ceci, et obtiens toujours l'erreur.

Ce code reproduira l'erreur:

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; 

Si vous trouvez pertinent, SELECT left(@@VERSION, 70) retours:

Microsoft SQL Server 2005 - 9.00.4053.00 (X64) May 26 2009 14:13:01 
+0

La requête fonctionne pour moi SS05 (X86 bien). Et, ça marche aussi sur mon SS08. Désolé, pas beaucoup d'aide là-bas, sauf que vous avez une bonne requête pour les autres versions. – bobs

+0

Ne fonctionne pas pour moi dans SS08 SP1 x86. –

+0

Cela ne fonctionne pas totalement sur mon instance SQL Server 2008 R2 Developer x64. Problème intéressant Ça commence à me sentir comme un insecte. Je veux dire, vous avez vraiment fait du bon boulot. –

Répondre

10

commentaire de Will A sur mon message original a trouvé la clé - la collation. Ma requête publiée a également fonctionné pour moi dans la base de données master.

L'examen de la collation a suggéré que j'étais sur la bonne voie.

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) 

quelques recherches frénétiques plus tard, j'ai eu cette monstruosité de code, qui

  1. spécifie explicitement le classement de chaque colonne,
  2. exécute avec succès, et
  3. renvoie les résultats attendus

À savoir:

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; 

assis magnifiquement dans ma fenêtre de résultats escomptée:

data_list 
------------------------------------------------ 
tsql rage;einstein.x.m;[email protected];[email protected]; 
+1

Je suis content que cela vous a envoyé dans la bonne direction, Einstein. –

+1

Pour l'enregistrement, cela devrait au moins être publié comme un problème MS Connect. Ils devraient au moins vous donner un meilleur message d'erreur. C'est assez opaque pour moi. Question SQL Server la plus difficile que j'ai jamais vue sur SO! –

+0

Merci, merci, merci! : DI avait exactement la même erreur, avec la différence de type de données ajoutée aussi (cela m'a pris un moment pour comprendre que j'avais les deux problèmes à la fois), mais sans l'aide de collation, je m'aurais probablement pris des jours pour comprendre était faux (partie d'une structure de requête/db grande et complexe).Merci à vous deux (@WillA) encore! :) –