CTE错误:"锚定部分和递归部分之间类型不匹配"。

74
我正在执行以下语句:
;WITH cte AS (
  SELECT 
    1 as rn, 
    'name1' as nm
  UNION ALL
  SELECT 
    rn + 1,
    nm = 'name' + CAST((rn + 1) as varchar(255))
  FROM cte a WHERE rn < 10)
SELECT * 
FROM cte

...以错误结束...

Msg 240, Level 16, State 1, Line 2
Types don't match between the anchor and the recursive part in column "nm" of recursive query "cte".

我在哪里犯了错误?
9个回答

121

这段代码的意思是:

'name1''name' + CAST((rn+1) as varchar(255)) 数据类型不同。

可以尝试以下代码(未测试):

;with cte as
(
select 1 as rn, CAST('name1' as varchar(259)) as nm
union all
select rn+1,nm = 'name' + CAST((rn+1) as varchar(255))
from cte a where rn<10)
select * from cte

基本上,你还需要确保长度也匹配。对于递归部分,如果再次失败,可能需要使用CAST('name' AS varchar(4))


先生,那就是我刚刚所做的。CAST(1 as varchar(255)) - priyanka.sarkar
7
再次感谢 Stackoverflow 在我提问之前就已经解答了我的问题。感谢 @priyanka 和 @gbn。 - Nathan Koop
7
如果你仍然遇到这个错误,你需要确保数据库的排序规则以及表的排序规则相同。换句话说,在CTE递归查询中,排序规则应该是相同的。 - Saeed Neamati

29

你需要转换两个 nm 字段的类型

;with cte as
(
select  1 as rn, 
        CAST('name1' AS VARCHAR(255)) as nm
union all
select  rn+1,
        nm = CAST('name' + CAST((rn+1) as varchar(255)) AS VARCHAR(255))
from cte a where rn<10)
select * from cte

那就是我刚刚做的。CAST(1 as varchar(255))。一个愚蠢的错误,忘记了转换类型。 - priyanka.sarkar
1
在与 SQL 斗争后,我最终将两者都转换为十进制数,这解决了我的问题。谢谢! - sheldonhull

12

对我来说,问题在于不同的排序规则。

只有这个方法对我有帮助:

;WITH cte AS (
  SELECT 
    1 AS rn, 
    CAST('name1' AS NVARCHAR(4000)) COLLATE DATABASE_DEFAULT AS nm
  UNION ALL
  SELECT 
    rn + 1,
    nm = CAST('name' + CAST((rn + 1) AS NVARCHAR(255)) AS NVARCHAR(4000)) COLLATE DATABASE_DEFAULT
  FROM cte a WHERE rn < 10)
SELECT * 
FROM cte;
希望它能帮助其他人。

4
;with cte as
(
select 1 as rn, 'name' + CAST(1 as varchar(255)) as nm
union all
select rn+1,nm = 'name' + CAST((rn+1) as varchar(255))
from cte a where rn<10)
select * from cte

7
你的回答和其他人的一样,你可以编辑其中一个并删除这个。像我这样的未来读者会因为更清晰而感激你 ;) - bluish

1
在我的情况下,我弄混了UNION ALL语句的顶部和底部子句中列的顺序。结果出现一个varchar列“位于”一个int列之下。如果有很多列,这是一个容易犯的错误。

非常感谢!!!这是对我有效的解决方案。一个非常容易被忽视的问题。 - Yoosaf Abdulla

1
如果您在递归公用表达式的递归项中使用CONCAT,由于CONCAT的输出类型是varchar(MAX),因此您只需要在初始查询中转换列:
WITH rcte AS (
    SELECT 1 AS nr, CAST('1' AS varchar(MAX)) AS trail
    UNION ALL
    SELECT nr+1, CONCAT(trail, '/', nr+1)
    FROM rcte
    WHERE nr < 5
)
SELECT * FROM rcte;

enter image description here


0
WITH rcte AS (
    SELECT 1 AS nr, CAST('1' AS varchar(MAX)) AS trail
    UNION ALL
    SELECT nr+1, cast(CONCAT(trail, '/', nr+1) as varchar(max))
    FROM rcte
    WHERE nr < 5
)
SELECT * FROM rcte;

请不要仅仅发布代码作为答案,还请解释一下这个答案如何帮助解决问题的背景。 - Arun Vinoth-Precog Tech - MVP
这将在没有任何错误的情况下给出上述输出。如果您执行上述查询,它将在SQL中给出错误。因此,我使用了转换函数来使其无误。 - bhuneshwar singh

0
我建议使用nvarchar(max)。
WITH CTE AS (
SELECT x,x_name FROM (VALUES (1,CAST('' AS nvarchar(MAX)))) AS     test(x,x_name)
UNION ALL
SELECT x + 1 x, CONCAT(x_name,x+1)  FROM CTE WHERE x < 10 )
SELECT * FROM CTE

-4
;with tmp1(NewsId,DataItem ,HeaderText)
 as
  (

    select NewsId, LEFT(HeaderText, CHARINDEX(',',HeaderText+',')-1),
    STUFF(HeaderText, 1, CHARINDEX(',',HeaderText+','), '') 
    from Currentnews

    union all

    select NewsId, LEFT(HeaderText, CHARINDEX(',',HeaderText+',')-1),
    STUFF(HeaderText, 1, CHARINDEX(',',HeaderText+','), '')
    from tmp1
    where HeaderText > ''

   )

   select NewsId, DataItem
   from tmp1
   order by NewsId

没有适当的格式,这是不可能阅读的。请参阅如何格式化我的代码块 - zealoushacker
1
他可能是新手(: 我也曾经是 - priyanka.sarkar
我一直在使用您提供的确切查询,但仍然出现与问题描述相同的错误。 - Oedhel Setren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接