查询不会将nvarchar(30)转换为小数

时间:2019-02-10 18:38:09

标签: sql sql-server

我有以下查询,该查询在运行时会出现以下错误:

Conversion failed when converting the nvarchar value '247.300' to data type int.

查询如下:

SELECT UD.SerialNumber,
       UD.ReadingDate,
       UD.ChannelName,
       CONVERT(decimal(18,2), ChannelValue) - LAG(CONVERT(decimal(18,2), ChannelValue),1,
       CONVERT(decimal(18,2), ChannelValue)) OVER (PARTITION BY ChannelName, 
       CASE ChannelValue WHEN 0 THEN 0 ELSE 1 END ORDER BY ReadingDate ASC)
FROM [Staging].[UriData] UD
WHERE UD.ChannelName IN (SELECT ChannelName FROM [Staging].[ActiveChannels])
ORDER BY ReadingDate;

这里是一个小提琴:DB Fiddle

小提琴(工作正常)与此处的查询之间的唯一区别是,我必须拥有ChannelValueNVARCHAR,因为某些数据将以文本形式出现。我已经过滤掉了查询中的所有文本数据。

我还通过以下查询对其进行了测试,但数据未显示。如果不是数字,我希望它会出现在这里。

select ChannelValue
from [Staging].[UriData]
where try_convert(numeric(18, 2), ChannelValue) is null and ChannelValue is not null;

预期结果是将数字“ 247.300”转换为数字并进行处理。为什么不转换?

2 个答案:

答案 0 :(得分:2)

如果您阅读错误消息,则会抱怨int

这来自此处的隐式转换

CASE ChannelValue WHEN 0 THEN 0 ELSE 1 END

使用显式强制转换

 CASE CONVERT(decimal(19,3), ChannelValue) WHEN 0 THEN 0 ELSE 1 END

然后,诸如247.300之类的值将转换为精细值并与整数0相类似。

尽管您也说“我已过滤掉查询中的所有文本数据。”。在这种情况下,无论如何都应始终使用TRY_CONVERT,以防操作被排序,从而使转换发生在过滤器之前。

答案 1 :(得分:0)

您不能轻易地在SQL Server中过滤掉文本值-数据库保留重新安排操作的权利,这可能会导致错误。

因此,请使用TRY_CONVERT()

SELECT UD.SerialNumber,
       UD.ReadingDate,
       UD.ChannelName,
       (TRY_CONVERT(decimal(18, 2), ChannelValue) -
        TRY_CONVERT(DECIMAL(18, 2), LAG(ChannelValue), 1, ChannelValue) OVER (PARTITION BY ChannelName, CASE ChannelValue WHEN '0' THEN 0 ELSE 1 END ORDER BY ReadingDate ASC))
       )
FROM [Staging].[UriData] UD
WHERE UD.ChannelName IN (SELECT ChannelName
                         FROM [Staging].[ActiveChannels]
                        )
ORDER BY ReadingDate;

如果ChannelValue是字符串,则CASE中的比较应该是字符串值。

在大多数情况下,您只需进行一次转换。但是,为了避免减法问题,还必须在减法之前进行转换。

您可以使用此逻辑来简化:

SELECT UD.SerialNumber,
       UD.ReadingDate,
       UD.ChannelName,
       (ChannelValue_d -
        LAG(ChannelValue_d), 1, ChannelValue_d) OVER (PARTITION BY ChannelName, CASE ChannelValue WHEN '0' THEN 0 ELSE 1 END ORDER BY ReadingDate ASC)
       )
FROM [Staging].[UriData] UD CROSS APPLY
     (VALUES (TRY_CONVERT(decimal(18, 2), ChannelValue) )
     ) v(ChannelValue_d)
WHERE UD.ChannelName IN (SELECT ChannelName
                         FROM [Staging].[ActiveChannels]
                        )
ORDER BY ReadingDate;