【问题标题】:Error with casting投射错误
【发布时间】:2012-10-16 08:38:28
【问题描述】:

我有一个查询,我必须从 varchar 列中提取一些数字字段。 当我在 select 语句中进行一些替换和子字符串并将其转换为 bigint 时,一切正常,但是当我在 join 中使用相同的转换时,它会引发错误 “将数据类型 varchar 转换为 bigint 时出错”。 这怎么可能?

select CAST(
        case when CHARINDEX('/',f.BML,1)>0 
            then substring(replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') ,1,CHARINDEX('/',BML,1)-1)
        else replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') 
        end as bigint)
from TableN n join TableO o  on
    n.Id=o.Id 
    join TableF f on
        f.OId=o.OId and
        substring(cast(n.RJ as varchar(10)),1,3)=substring(CAST(f.MT AS varchar(10)),1,3) and
    CAST(
        case when CHARINDEX('/',f.BML,1)>0 then substring(replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') ,1,CHARINDEX('/',f.BML,1)-1)
        else replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') 
        end as bigint) =n.mbr
order by n.Ident

【问题讨论】:

  • 我猜您的varchar 列中有无法转换为bigint 的值。
  • @Mikael Eriksson 但是相同的演员如何在 select 语句中传递?它应该抛出相同的异常。
  • 您是否有一个 where 子句过滤掉导致错误的行?
  • 连接可能会查看表中的所有行。在字段列表中使用时,转换可能仅应用于实际返回的行。
  • 我们看不到您的查询 - 但请注意,在 SQL 中检查条件的顺序几乎没有保证(如果有的话) - 因此,如果您有类似 WHERE Column LIKE '[0-9]' and CONVERT(bigint,Column) = 5 的条件,它可能会阻碍转换。

标签: sql-server-2008 casting varchar


【解决方案1】:

正如我在评论中指出的那样,我们无法保证评估条件的顺序。所以如果你有:

    f.OId=o.OId and
    substring(cast(n.RJ as varchar(10)),1,3)=substring(CAST(f.MT AS varchar(10)),1,3) and
CAST(
    case when CHARINDEX('/',f.BML,1)>0 then substring(replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') ,1,CHARINDEX('/',f.BML,1)-1)
    else replace(replace(replace(replace(replace(replace(replace(replace(replace(f.BML,'A',''),'B',''),'C',''),'+',''),',',''),'S',''),'H',''),'P',''),'¸','') 
    end as bigint) =n.mbr

并且f.OId=o.OIdsubstring(cast(n.RJ as varchar(10)),1,3)=substring(CAST(f.MT AS varchar(10)),1,3) 应该消除不能转换为bigint 的值为BML 的行,这不能保证不会尝试转换。


您可以尝试将应该消除不良BML 值的过滤器移动到子查询或CTE 中,但这仍然不能保证查询优化器不会将转换运算符下推到子查询中并且仍然会导致错误。

处理这个问题的唯一真正方法(不幸的是)是将查询分成两部分,消除第一个查询中不可转换的值,并将此查询的结果放在临时表/表变量中。然后使用这个临时表构建查询的后半部分。

【讨论】:

  • 我考虑过转移到临时表,但这会使查询更加复杂。这是我需要查找重复数据的一次性查询。好吧,我想没有别的办法了。无论如何,谢谢你,达米安。