【问题标题】:CTE Error : Types don't match between the anchor and the recursive partCTE 错误:锚点和递归部分之间的类型不匹配
【发布时间】:2019-05-01 06:29:39
【问题描述】:

执行以下查询:

WITH cte AS (
    SELECT CAST('" + mindate+ "' as varchar(255))  as fdate
    UNION ALL
    SELECT CAST(DATEADD(day, 1, fdate) as date)
    FROM cte
    WHERE fdate < '" + tday+"'
)
SELECT COUNT(fdate) AS Fdate
FROM cte left join tbl_Attendence on cte.fdate = tbl_Attendence.Datess
where tbl_Attendence.Datess is null

但我以以下错误结束:

锚点和列中递归部分的类型不匹配 递归查询“cte”的“fdate”。

【问题讨论】:

  • 既然你有明确的演员表,你怎么能混淆?您是说 fdate 在 CTE 的第一部分是 varchar(255) 在递归部分是 date
  • fdate 和 date 都有不同的数据类型,这会导致错误
  • 如果您要多次编写此类查询,通常值得投入少量时间来创建日历表。每天填充一行,然后可以轻松地用于这样的查询,20 年的数据仍然少于 10000 行。
  • 查询中有很多错误,您只需选择一个字符串 varchar 值 "+ mindate +" 作为 fdate 并使用 CTE 尝试将该 varchar 值转换为日期类型,这在任何语言中都是不可能的.我建议您使用强制转换值进行一个简单的查询,以便您能够理解您在那里做错了什么,或者尝试解释您的要求并为此提供一个场景。

标签: sql sql-server common-table-expression


【解决方案1】:

union中的所有记录必须有相同的列和相同的列名,你使用了fdate和date,你应该为列使用相同的名称

WITH cte AS (
    SELECT CAST('" + mindate+ "' as varchar(255))  as fdate
    UNION ALL
    SELECT CAST(DATEADD(day, 1, fdate) as fdate)
    FROM cte
    WHERE fdate < '" + tday+"'
)
SELECT COUNT(fdate) AS Fdate
FROM cte left join tbl_Attendence on cte.fdate = tbl_Attendence.Datess
where tbl_Attendence.Datess is null

【讨论】:

  • Union 的结果集不必匹配列名,只需匹配数量和类型。试试这个,它会工作:SELECT 1 AS A UNION ALL SELECT 2 AS B.
【解决方案2】:

这是您的原始查询:

WITH cte AS 
(
    SELECT 
        CAST('" + mindate+ "' as varchar(255)) as fdate 

    UNION ALL 

    SELECT 
        CAST(DATEADD(day, 1, fdate) as date) 
    FROM 
        cte 
    WHERE 
        fdate < '" + tday+"' 
)
SELECT 
    COUNT(fdate) AS Fdate 
FROM 
    cte 
    left join tbl_Attendence on cte.fdate = tbl_Attendence.Datess 
where 
    tbl_Attendence.Datess is null

问题是 CTE 内的第一个 SELECTVARCHAR(255) 类型,而它的联合对应物(CTE 内的第二个 SELECT)是 DATE 类型。由于您将这些结果相加,因此数据类型必须匹配。

有一个WHERE (fdate &lt; '" + tday+"') 正在比较字符串值。在我看来,您希望这是动态 SQL。如果不先构建字符串,它将无法在普通 SQL 上工作。

我无法提出解决方案,因为我不知道您要完成什么。


如果 Damien 的建议是正确的,您可以使用以下方法找出 tbl_Attendence 中缺少的日期数量:

DECLARE @MinDate DATE = '2018-01-01'

DECLARE @MaxDate DATE = GETDATE()

;WITH cte AS 
(
    SELECT 
        @MinDate as fdate 

    UNION ALL 

    SELECT 
        DATEADD(day, 1, fdate) as fdate
    FROM 
        cte 
    WHERE 
        fdate < @MaxDate
)
SELECT 
    COUNT(fdate) AS Fdate 
FROM 
    cte 
where 
    NOT EXISTS (SELECT 'not in tbl_Attendence' FROM tbl_Attendence AS T WHERE T.Datess = cte.fdate)
OPTION
    (MAXRECURSION 0)

【讨论】:

  • 如果我已经正确解码了逻辑,那就是“找出这两个日期之间没有出勤记录的天数”
  • @Damien_The_Unbeliever 是的,好像是这样。
【解决方案3】:

来自官方docs,你有:

递归成员中列的数据类型必须与 锚成员中对应列的数据类型。

检查所有规则并确保您遵守它们。

【讨论】:

    猜你喜欢
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 2014-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多