CTE 错误(nvarchar 到数字)

And*_*ndy 5 sql-server cte

我正在使用 CTE 将 SSRS 存储的 proc 转换为 BO 存储的 proc,因为显然我不能将临时表与 Business Objects 一起使用。

我有这个查询:

;WITH cte1
AS
( 
    SELECT  cv.issue  
          , cv.customfield  
          , CAST(STRINGVALUE AS NUMERIC) AS priority_num  
    --INTO    #temp_priority_val  
    FROM    proddb1.customfieldvalue cv WITH (NOLOCK)  
            INNER JOIN proddb1.customfield e WITH (NOLOCK)
                 ON  cv.CUSTOMFIELD = e.id 
                 AND e.cfname = 'Issue Priority')  

,cte2
AS
( 
    SELECT  a.ISSUE  
          , f.customvalue priority_num  
    --INTO    #temp_priority  
    FROM    cte1 a 
            INNER JOIN proddb1.customfieldoption f WITH (NOLOCK)
                 ON  a.CUSTOMFIELD = f.CUSTOMFIELD        
                 AND CAST(a.priority_num AS NUMERIC) = f.id) 

SELECT * FROM cte2 
Run Code Online (Sandbox Code Playgroud)

我一直Error converting data type nvarchar to numeric.在执行此操作时出错。该priority_num列是在第一个 CTE 中进行 CAST 的 nvarchar 列。当我在具有临时表的原始语句中执行此操作时,它运行良好。它必须与 CTE 范围有关吗?

Aar*_*and 11

您无法轻松控制 SQL Server 评估未使用正确数据类型(或精度不匹配)的列的内容的顺序。如果您尝试将 nvarchar 列强制转换为数字,即使您的过滤器应该排除所有非数字值,SQL Server 仍然可以先尝试这些(请参阅Erland 在 UserVoice 上对此的抱怨)。在某些情况下,您可以嵌套 CTE,直到奶牛回家,但 SQL Server 仍会将该评估推送或拉到您没有预料到的地方。

只要不涉及聚合和全文函数(请参阅此处此处),您就可以在转换之前使用CASE表达式强制执行此评估。这是您的查询的简化版本,没有 CTE:

SELECT cfv.issue,
  priority_num = CONVERT(NUMERIC(something, something), 
    CASE WHEN ISNUMERIC(cfo.customvalue)=1 THEN cfo.customvalue END)
FROM
  proddb1.customfieldvalue AS cfv
  INNER JOIN proddb1.customfield AS cf
  ON cfv.CUSTOMFIELD = cf.id
  INNER JOIN proddb1.customfieldoption AS cfo
  ON cfv.CUSTOMFIELD = cfo.CUSTOMFIELD
  AND CONVERT(NUMERIC(something, something), 
    CASE WHEN ISNUMERIC(cfo.customvalue)=1 THEN cfo.customvalue END) = cfo.id
  WHERE cf.cfname = 'Issue Priority';
Run Code Online (Sandbox Code Playgroud)

您将需要更改something, something为正确的精度/比例(int如果不需要小数位,则使用其中一种类型)。你不应该在没有指定长度的情况下声明不同的类型 -这篇博文是关于 varchar,但它确实适用于所有类型

如果您使用的是 SQL Server 2012(包含您使用的 SQL Server 版本等信息总是有用的),您可以简化此操作:

CONVERT(NUMERIC(something, something), 
    CASE WHEN ISNUMERIC(cfo.customvalue)=1 THEN cfo.customvalue END)
Run Code Online (Sandbox Code Playgroud)

对此:

TRY_CONVERT(NUMERIC(something, something), cfo.customvalue)
Run Code Online (Sandbox Code Playgroud)

它实际上会更可靠(因为ISNUMERIC可以返回 1 并且在特定类型的转换时仍然失败)。早在 2002 年,我就用这种方式写过博客