关于 sql: 加入前未过滤数据

Data not filtering before a join

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

1
2
3
4
5
6
7
8
9
10
11
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

Msg 245, Level 16, State 1, Line 1
将 varchar 值"N0007"转换为数据类型 int 时转换失败。表别名 b 实际上是一个视图。

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

编辑:

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


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

1
2
3
4
5
6
7
8
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 应该可以解决这个问题。我不认为它比您最初想要的效率低得多,因为如果首先完成 isnumeric,无论如何都会强制进行表扫描。


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


ISNUMERIC() 以不可靠而闻名。你将需要一个替代方案,我一直在寻求这样的替代方案。


也许 N 被认为是货币符号?您可以尝试用

替换 IsNumeric

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

或者只是

1
LIKE '[0-9]%'

如果字母不能在中间