加入前未过滤数据

Posted

技术标签:

【中文标题】加入前未过滤数据【英文标题】:Data not filtering before a join 【发布时间】:2008-12-03 22:54:42 【问题描述】:

来自同事的一个我无法弄清楚的谜题......

update  btd.dbo.tblpayroll
set     empname = ( select  b.Legal_Name
                    from    ( SELECT    Legal_Name,
                                        Employee_ID
                              FROM      Com.dbo.Workers
                              WHERE     isnumeric(Employee_ID) = 1
                            ) b
                    where   b.Employee_ID = empnum
                            and b.Legal_name is not NULL
                  )
where   empname is NULL

消息 245,第 16 级,状态 1,第 1 行 将 varchar 值“N0007”转换为数据类型 int 时转换失败。表别名 b 实际上是一个视图。

值“N0007”在 Workers 表中。我不明白为什么它没有从正在加入的结果中过滤出来。

编辑:

事实上,别名确实返回了正确的行 - 所以 isNumeric 正在完成这项工作。

【问题讨论】:

【参考方案1】:

我怀疑优化器试图在内部选择之前应用外部选择的 where 子句。大概它认为它能够对 Employee_ID 进行索引查找,从而在这种情况下实现更快的查询。试试:

update  btd.dbo.tblpayroll
set     empname = ( select Legal_Name
                    from Com.dbo.Workers
                    where  isnumeric(Employee_ID) = 1
                           and convert(varchar,Employee_ID)
                             = convert(varchar,empnum) 
                           and Legal_name is not NULL)
where   empname is NULL

将它们全部转换为 varchar 应该会处理好它。我不认为它的效率比你最初想要的要低得多,因为如果先完成非数字,无论如何都会强制进行表扫描。

【讨论】:

我也认为是优化器。其中 b.Employee_ID = CAST(empnum AS VARCHAR) 应该有帮助 我尝试查看解释计划,看看我是否能发现它 - 但我并不精通阅读它们。您的查询在实际查询中运行良好。谢谢。 @Stanislav -- 我不确定每种类型是什么类型,所以我认为将两者都转换为 varchar 是最安全的选择。【参考方案2】:

ISNUMERIC() 对于您正在尝试做的事情是出了名的不可靠。你需要an alternative, which I've been asking for here,比如this one。

【讨论】:

【参考方案3】:

显而易见的事情是强制比较的顺序,可能是通过从只有数字 Employee_ID 的视图中获取名称,而不是完整的 Workers 表。

【讨论】:

不幸的是,显而易见的答案是我们首先要做的事情 - 并且令人惊讶地具有相同的行为。【参考方案4】:

也许 N 被认为是货币符号?您可以尝试将 IsNumeric 替换为

LIKE REPLICATE('[0-9]',/*length of Employee_ID*/) 

或者只是

LIKE '[0-9]%' 

如果字母不能在中间

【讨论】:

以上是关于加入前未过滤数据的主要内容,如果未能解决你的问题,请参考以下文章

Rails:保存前未使用 assign_attributes 保存数据

加入和过滤掉不必要的数据

加入大数据帧和小数据帧时的广播数据帧和过滤器

Django,从反向外键查询添加数据(外键加入过滤器)

多次加入同一个表以每次使用过滤器检索不同的数据

restify cors 飞行前未连接