当前位置: 首页 > 面试题库 >

在WHERE子句过滤掉错误值之前,将执行SELECT中的MSSQL cast([varcharColumn]到int)

毕宏盛
2023-03-14
问题内容

请忽略在varchar列中具有值(我们期望是整数)的令人毛骨悚然的设计问题。

create table dbo.Parent (
    Id bigint NOT NULL,
    TypeId int NOT NULL
)

create table dbo.Child (
    Id bigint NOT NULL,
    ParentId bigint NOT NULL,
    TypeId int NOT NULL,
    varcharColumn varchar(300) NULL
)

select cast(c.varcharColumn as int)
from dbo.Parent p (nolock)
    inner join dbo.Child c (nolock)
        on p.Id = c.ParentId
            and c.TypeId = 2
where p.TypeId = 13

休息时间:

由于无法将其转换为int的值,因此发生了强制转换。在这种情况下:“ 123-1”。奇怪的是,要转换的值会从最终结果集中过滤掉。

例如,这将返回零结果

select c.varcharColumn
from dbo.Parent p (nolock)
    inner join dbo.Child c (nolock)
        on p.Id = c.ParentId
            and c.TypeId = 2
where p.TypeId = 13
    and c.varcharColumn = '123-1'

查询计划最终查看了子表,并在where子句之前实际应用了强制转换功能。

我们能够通过在子表上创建新索引来解决此问题(它正在执行PK 扫描

create index [NCIDX_dbo_Child__TypeId] on dbo.Child (
    TypeId
)
include (
    ParentId,
    varcharColumn
)

现在,它首先过滤父表的where子句。

没有额外的索引,有什么方法可以解决此问题?同样,请避免提出任何与修复我们的架构有关的建议。在这种情况下,这绝对是正确的解决方法。

我最想了解的是为什么它在过滤结果集之前应用了强制类型转换。

谢谢

编辑-答案:

非常感谢亚伦和戈登。如果我获得超过15个代表点,我会回头再谈您的两个回答。

我们最终需要Gordon的答案,因为我们想在视图中使用此查询。办公室中的一些人对使用案例声明感到谨慎,因为他们希望对确保我们首先拥有较小的结果集(Aaron的答案)有更多的控制权,但是这全都归结为查看查询计划并检查您的阅读结果计数。

再次感谢您的所有答复!


问题答案:

首先,这不是一个“明显的设计问题”。SQL是输出的描述性语言,而不是指定如何进行练习的过程性语言。通常,不能保证处理顺序,这是一个优势。我可能会说存在一个设计问题,但这是有关SQL语句中异常的一般处理。

根据SQL Server文档(http://msdn.microsoft.com/zh-cn/library/ms181765.aspx),
对于标量表达式 ,您可以依赖CASE语句的评估顺序。因此,以下应该工作:

select (case when isnumeric(c.varcharColumn) = 1 then cast(c.varcharColumn as int) end)

或者,更接近“ int”表达式:

select (case when isnumeric(c.varcharColumn) = 1 and c.varcharColumn not like '%.%' and c.varcharColumn not like '%e%'
             then cast(c.varcharColumn as int)
        end)

至少您的代码正在执行显式的CAST。当强制转换是隐式的(并且有数百列)时,这种情况更加糟糕。



 类似资料:
  • 问题内容: 在我的表中,我有一个可为空的bit列(旧系统…),另一位开发人员最近对存储过程进行了更改,以仅显示bit列不为真的值(1)。因为这是一个可为空的列,所以我们注意到,如果该列为NULL,则不会选择该记录。为什么是这样? 我和其他开发人员都同意NULL <> 1 …这是SQL中的错误还是设计这种方式?似乎是设计缺陷。 当前代码: 建议的修复: (Jon Erickson) VoidedIn

  • 为什么可以在where子句中包含而只保留字母? 编辑1这里是解释:

  • 问题内容: 在WHERE子句中有使用SELECT语句描述的名称吗?这是好/不好的做法吗? 这会是更好的选择吗? 它远没有那么优雅,但是运行起来比以前的版本要快。我不喜欢它,因为它在GUI中没有非常清晰地显示(并且SQL初学者需要理解它)。我可以将其分为两个独立的查询,但是随后事情变得混乱了…… 注意:我不仅需要日期和分数(例如姓名) 问题答案: 称为相关子查询。它有它的用途。

  • 问题内容: 我将如何在没有硬编码值的情况下编写此sql语句? 宁愿有这样的事情: 提前致谢.. 问题答案: 用您当前的方式构造SQL查询是一个糟糕的主意,因为它为各种SQL注入攻击打开了大门 。为了正确执行此操作,您必须改为使用“ 预备语句”。这也将解决您目前显然遇到的各种逃避问题。 请注意,这是一个昂贵的调用(除非您的应用程序服务器使用语句缓存和其他类似的功能)。从理论上讲,最好先准备一次语句,

  • 我正在为一个SQL的实现工作,它应该在Where和Having子句之间使用联合操作来显示结果。例如, sql语句的目的是返回同时满足where和having条件的结果集。 resultset1<=select*from table1,其中col1='get';resultset2<=select*from table1 group by col2 avg(col3)>30 final result

  • 问题内容: 我正在尝试比较两个表以在每个表中找到不在另一个表中的行。表1的groupby列用于在表1中创建2组数据。 表2只有一栏。 因此,表1在组2中具有值1,2,4,表2具有值1,3,4。 加入第2组时,我期望得到以下结果: 我可以使它起作用的唯一方法是在第一个联接中放置where子句: 第二个在“打开”中有一个过滤器: 谁能提出一种不在on子句中而是在where子句中使用过滤器的方法? 上下