首页 > 解决方案 > 在 nvarchar 列上使用 between 子句查找范围不起作用

问题描述

我有 3 个 nvarchar 列 user_3、user_4 和描述。我正在设置是和否标志。如果描述列中的值相等或介于 user_3 和 User4 之间,则将标志设置为“N”,否则将标志设置为“Y”。

这是我到目前为止编写的 SQL 脚本。它在某些情况下有效,但并非总是如此。查看带有结果的图像。例如,它在第 1 行有效,但在第 6 行无效。我究竟做错了什么?

SELECT  [B].USER_3,[B].USER_4,A.DESCRIPTION,
(case when Isnumeric(A.DESCRIPTION) <> 1 then 'Y' 
else case when (CASE WHEN Isnumeric(A.DESCRIPTION) = 1 then
cast(A.DESCRIPTION AS decimal(10,5)) else 0 end) 
between ( CASE WHEN Isnumeric([B].USER_4) = 1 then 
cast([B].USER_4 AS decimal(10,5)) else 0 end) and
(CASE WHEN Isnumeric([B].USER_3) = 1 then cast([B].USER_3  AS decimal(10,5)) else 0 end)
then 'N' else 'Y' end end) as Flagset
from A , B

这是结果的屏幕截图

在此处输入图像描述

标签: sql-servercastingsql-server-2012betweenisnumeric

解决方案


问题在于您BETWEEN按照文档使用:

如果 test_expression 的值大于或等于 begin_expression 的值且小于或等于 end_expression 的值,则 BETWEEN 返回 TRUE。

因为不知道是上限USER_3还是USER_4下限,所以需要双向测试。

注意:对于这种查询,我更喜欢预先计算CROSS APPLY我需要的所有值(在这种情况下使用)。它使跟踪和调试变得更加容易。

SELECT USER_3, USER_4, [DESCRIPTION]

    , CASE WHEN ISNUMERIC([DESCRIPTION]) <> 1 THEN 'Y' ELSE
        CASE WHEN CASE WHEN ISNUMERIC([DESCRIPTION]) = 1 THEN CAST([DESCRIPTION] AS decimal(10,5)) ELSE 0 END BETWEEN CASE WHEN ISNUMERIC(USER_4) = 1 THEN CAST(USER_4 AS decimal(10,5)) ELSE 0 END AND
        CASE WHEN ISNUMERIC(USER_3) = 1 THEN CAST(USER_3  AS decimal(10,5)) ELSE 0 END
    THEN 'N' ELSE 'Y' END END AS Flagset

    , CASE WHEN DNUMERIC <> 1 THEN 'Y' ELSE CASE WHEN DESCRIPTIOND BETWEEN USER_4D AND USER_3D OR DESCRIPTIOND BETWEEN USER_3D AND USER_4D THEN 'N' ELSE 'Y' END END CorrectedFlagSet

FROM (VALUES
    ('1.395','1.385','1.390')
    , ('22.025','41.425','22')
    , ('22.025','41.425','23.025')
) AS X (USER_3, USER_4, [DESCRIPTION])
CROSS APPLY (VALUES (
    CASE WHEN ISNUMERIC(USER_3) = 1 THEN CAST(USER_3 AS decimal(10,5)) ELSE 0 END
    , CASE WHEN ISNUMERIC(USER_4) = 1 THEN CAST(USER_4 AS decimal(10,5)) ELSE 0 END
    , CASE WHEN ISNUMERIC([DESCRIPTION]) = 1 THEN CAST([DESCRIPTION] AS decimal(10,5)) ELSE 0 END
    , CASE WHEN ISNUMERIC([DESCRIPTION]) = 1 THEN 1 ELSE 0 END
)) AS Y (USER_3D, USER_4D, DESCRIPTIOND, DNUMERIC);

回报:

USER_3 USER_4 描述 标志集 更正标志集
1.395 1.385 1.390 ñ ñ
22.025 41.425 22
22.025 41.425 23.025 ñ

我敢肯定,我不必提及您确实应该首先以数字形式存储这些数据,因为它会表现得更好并为您节省很多未来的问题。

布局合理且大小写一致的查询也有助于理解和调试它们。

最后提供一个包含示例数据、您的查询和所需结果的最小可重复示例,如此处所示,使人们更容易提供帮助。


推荐阅读