TSQL CTE 错误“锚点和递归部分之间的类型不匹配”

TSQL CTE error ''Types don't match between the anchor and the recursive part"

有人可以帮助我了解以下错误的详细信息吗?这适用于 SQL Server 2008。

我确实自己修复了它,并发现许多显示相同修复的搜索结果,但是 none 解释为什么在 CTE 中会发生这种情况。

Types don't match between the anchor and the recursive part in column "txt" of recursive query "CTE".

这是我用 CAST 解决问题的示例,但为什么它有效?

WITH CTE(n, txt) AS
(
    --SELECT      1, '1'                          --This does not work.
    --SELECT      1, CAST('1' AS varchar)         --This does not work.
    --SELECT      1, CAST('1' AS varchar(1000))   --This does not work.
    SELECT      
        1, 
        CAST('1' AS varchar(max))                 --This works. Why?
    UNION ALL
    SELECT      
        n+1, 
        txt + ', ' + CAST(n+1 AS varchar)         --Why is (max) NOT needed?
    FROM        
        CTE
    WHERE       
        n < 10
)
SELECT *
FROM CTE

我假设有一些我不理解的默认变量类型在起作用,例如:

如果将查询放入字符串中,则可以获得与查询类似的结果集数据类型:

DECLARE @query nvarchar(max) = 'SELECT * FROM table_name';

EXEC sp_describe_first_result_set @query, NULL, 0;  

您要的信息是all in the documentation:

When concatenating two char, varchar, binary, or varbinary expressions, the length of the resulting expression is the sum of the lengths of the two source expressions, up to 8,000 bytes.

snip ...

When comparing two expressions of the same data type but different lengths by using UNION, EXCEPT, or INTERSECT, the resulting length is the longer of the two expressions.

The precision and scale of the numeric data types besides decimal are fixed. When an arithmetic operator has two expressions of the same type, the result has the same data type with the precision and scale defined for that type.

但是,递归 CTE is not the same 作为正常 UNION ALL:

The data type of a column in the recursive member must be the same as the data type of the corresponding column in the anchor member.

所以回答你的问题:

  • 'Hello world!' 的数据类型默认为 varchar(12)
  • 'A' + 'B' 的数据类型为 varchar(2) 因为这是两种数据类型相加的总长度(实际值不相关)。
  • n+1 仍然是 int
  • 在递归 CTE 中,数据类型必须 完全匹配 ,因此 '1'varchar(1)。如果你在 CAST 中指定没有长度的 varchar 那么你会得到 varchar(30),所以 txt + ', ' + CAST(n+1 AS varchar)varchar(33).

当您将锚点部分转换为 varchar(max) 时,这自动意味着递归部分也将是 varchar(max)。你不需要强制转换为max,你也可以将递归部分直接强制转换为varchar(30) 例如:

WITH CTE(n, txt) AS
(
    --SELECT      1, '1'                          --This does not work.
    SELECT      1, CAST('1' AS varchar(30))         --This does work.
    --SELECT      1, CAST('1' AS varchar(1000))   --This does not work.
    UNION ALL
    SELECT      
        n+1, 
        CAST(CONCAT(txt, ', ', n+1) AS varchar(30))
    FROM        
        CTE
    WHERE       
        n < 10
)
SELECT *
FROM CTE

db<>fiddle