以下表为例:
CREATE TABLE TBL_Names(Name VARCHAR(32))
INSERT INTO TBL_Names
VALUES ('Ken'),('1965'),('Karen'),('2541')木琴
执行以下查询会引发异常:
SELECT  [name]
FROM    dbo.tblNames AS tn
WHERE   [name] IN ( SELECT  [name]
                    FROM    dbo.tblNames
                    WHERE   ISNUMERIC([name]) = 1 )
        AND [name] = 2541当将varchar值'Ken‘转换为数据类型int时,Msg 245、级别16、状态1、第1行转换失败。
在执行以下查询时,不会出现错误:
SELECT  [name]
FROM    dbo.tblNames AS tn
WHERE   ISNUMERIC([name]) = 1
        AND [name] = 2541我知道这是因为SQL Server查询优化器的决定。但是,我想知道是否有任何方法可以使sql server按特定顺序计算子句。这样,在第一个查询中,第一个子句过滤掉那些不是数字的Names,以便第二个子句在转换为数字时不会失败。
更新:正如您可能注意到的那样,上面的查询只是说明问题的一个实例。我知道这种隐式转换的风险,并感谢那些试图警告我这一点的人。然而,我的主要问题是如何改变优化器在某一顺序下评估子句的行为。
发布于 2019-02-19 10:40:45
没有“直接”的方式告诉引擎按照顺序执行操作。SQL不是一种命令式语言,在这种语言中,您可以完全控制如何来做事情,您只需告诉您需要什么,而服务器决定如何自己完成它。
对于这种特殊情况,只要您有[name] = 2541,就会面临潜在的转换失败的风险,因为您是在比较VARCHAR列和INT。即使使用子查询/CTE,优化器仍有空间先计算这个表达式,然后尝试将所有varchar值转换为int (因此失败)。
你可以用一些变通的方法来逃避这个问题:
[name]转换为INT,并在不同的语句上进行比较。
声明@tblNamesInt表(nameInt INT)插入到@tblNamesInt ( nameInt)中,选择nameInt =从dbo.tblNames中转换( INT、name),其中TRY_CAST (名称为INT)不是NULL -- TRY_CAST优于INT SELECT * FROM * FROM @tblNamesInt,其中T.nameInt = 2351 --数据类型匹配即使是索引提示也不会迫使优化器使用索引(这就是为什么它被称为提示),因此我们对它如何完成任务几乎没有控制。
我们知道有几种机制是按顺序计算的,我们可以利用它们的优势,例如HAVING表达式总是在分组值之后计算,分组总是在WHERE条件之后。因此,我们可以“安全”地进行以下分组:
DECLARE @Table TABLE (IntsAsVarchar VARCHAR(100))
INSERT INTO @Table (IntsAsVarchar)
VALUES
    ('1'), 
    ('2'),
    ('20'),
    ('25'),
    ('30'),
    ('A') -- Not an INT!
SELECT
    CASE WHEN T.IntsAsVarchar < 15 THEN 15 ELSE 30 END,
    COUNT(*)
FROM
    @Table AS T
WHERE
    TRY_CAST(T.IntsAsVarchar AS INT) IS NOT NULL -- Will filter out non-INT values first
GROUP BY
    CASE WHEN T.IntsAsVarchar < 15 THEN 15 ELSE 30 END但是,您应该始终避免编写隐含转换的代码(如T.IntsAsVarchar < 15)。
发布于 2019-02-19 10:07:55
试着像这样
  SELECT  [name]
    FROM    #TBL_Names AS tn
    WHERE   [name] IN ( SELECT  [name]
                        FROM    #TBL_Names
                        WHERE   ISNUMERIC([name]) = 1 )
            AND  [name] = '2541'2)
AND  [name] =  convert(varchar,2541 )由于将名称存储为varchar(32),varchar将接受整数数据类型值(也称为优先级值)
发布于 2019-02-19 10:16:07
那麽:
SELECT *
FROM dbo.tblNames AS tn
WHERE [name] = convert(varchar, 2541)您为什么需要ISNUMERIC([name]) = 1),因为您只关心值'2541'
https://stackoverflow.com/questions/54763518
复制相似问题