首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >按一定顺序使SQL SERVER计算子句

按一定顺序使SQL SERVER计算子句
EN

Stack Overflow用户
提问于 2019-02-19 10:03:49
回答 5查看 104关注 0票数 3

以下表为例:

代码语言:javascript
运行
复制
CREATE TABLE TBL_Names(Name VARCHAR(32))

INSERT INTO TBL_Names
VALUES ('Ken'),('1965'),('Karen'),('2541')

木琴

执行以下查询会引发异常:

代码语言:javascript
运行
复制
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行转换失败。

在执行以下查询时,不会出现错误:

代码语言:javascript
运行
复制
SELECT  [name]
FROM    dbo.tblNames AS tn
WHERE   ISNUMERIC([name]) = 1
        AND [name] = 2541

我知道这是因为SQL Server查询优化器的决定。但是,我想知道是否有任何方法可以使sql server按特定顺序计算子句。这样,在第一个查询中,第一个子句过滤掉那些不是数字的Names,以便第二个子句在转换为数字时不会失败。

更新:正如您可能注意到的那样,上面的查询只是说明问题的一个实例。我知道这种隐式转换的风险,并感谢那些试图警告我这一点的人。然而,我的主要问题是如何改变优化器在某一顺序下评估子句的行为。

EN

回答 5

Stack Overflow用户

发布于 2019-02-19 10:40:45

没有“直接”的方式告诉引擎按照顺序执行操作。SQL不是一种命令式语言,在这种语言中,您可以完全控制如何来做事情,您只需告诉您需要什么,而服务器决定如何自己完成它。

对于这种特殊情况,只要您有[name] = 2541,就会面临潜在的转换失败的风险,因为您是在比较VARCHAR列和INT。即使使用子查询/CTE,优化器仍有空间先计算这个表达式,然后尝试将所有varchar值转换为int (因此失败)。

你可以用一些变通的方法来逃避这个问题:

  • 正确比较匹配的数据类型: 名称= '2541‘
  • 事先并仅在可能的情况下将[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条件之后。因此,我们可以“安全”地进行以下分组:

代码语言:javascript
运行
复制
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)。

票数 3
EN

Stack Overflow用户

发布于 2019-02-19 10:07:55

试着像这样

代码语言:javascript
运行
复制
  SELECT  [name]
    FROM    #TBL_Names AS tn
    WHERE   [name] IN ( SELECT  [name]
                        FROM    #TBL_Names
                        WHERE   ISNUMERIC([name]) = 1 )
            AND  [name] = '2541'

2)

代码语言:javascript
运行
复制
AND  [name] =  convert(varchar,2541 )

由于将名称存储为varchar(32),varchar将接受整数数据类型值(也称为优先级值)

票数 1
EN

Stack Overflow用户

发布于 2019-02-19 10:16:07

那麽:

代码语言:javascript
运行
复制
SELECT *
FROM dbo.tblNames AS tn
WHERE [name] = convert(varchar, 2541)

您为什么需要ISNUMERIC([name]) = 1),因为您只关心值'2541'

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54763518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档