SQL 通过连接两个表将 varchar 转换为 int 时出错

SQL error while converting varchar to int by joining two tables

我需要在我的数据库中查找丢失的号码。我正在比较两个数据库,在查询中使用数字 1 - 999 创建的 tempdb 和 MYDAT。

MYDAT 看起来像:

+-------+
|  id   |
+-------+
| A-001 |
| A-002 |
| A-004 |
| A-... |
| A-952 |
| A-... |
+-------+

我是运行这个查询:

declare @tempid int

set @tempid = 1

create table tempdb (tempid int)

while @tempid < 1000
begin
    insert into tempdb values(@tempid)
    set @tempid = @tempid + 1
end

select tempdb.tempid from tempdb
left join MYDAT on tempdb.tempid = CAST(SUBSTRING(MYDAT.ID, 3, 3) as INT)
where
MYDAT.ID IS NULL and
SUBSTRING(MYDAT.ID, 3, 3) <> '' and
SUBSTRING(MYDAT.ID, 3, 3) <> '000'and
SUBSTRING(MYDAT.ID, 3, 3)  NOT LIKE '%[^0-9]%'

drop table tempdb

在不删除 temdb 的情况下,select * from tempdb 看起来不错,我得到了我想要的。

从 MYDAT 中选择和转换数据的部分效果很好,我只得到整数

select CAST(SUBSTRING(MYDAT.ID, 3, 3) as INT) fom MYDAT
where 
SUBSTRING(MYDAT.ID, 3, 3) <> '' and
SUBSTRING(MYDAT.ID, 3, 3) <> '000'and
SUBSTRING(MYDAT.ID, 3, 3)  NOT LIKE '%[^0-9]%'

我遇到错误 "converting varchar to int" 但我不知道为什么。当我将左连接更改为右连接时,我没有收到任何错误。

我也手动检查了两个数据库,没有字符串或字符,只有整数。

我也尝试了 CONVERT() 但结果相同。

任何建议或想法是什么问题?

编辑:

1 - 我在 rextester 上尝试时看到一个错误。 I added MYDAT.ID IS NULL 到查询,以便我得到正确的结果。

2 - 示例 我需要这个:http://rextester.com/KFG73206

但是 CAST 或 CONVERT 似乎不起作用 http://rextester.com/WJIAH52304

无法明确说明原因,可能是数据的问题。您可以尝试一些解决方法来避免投射,

 create table tempdb (tempid varchar(3))

while @tempid < 1000
begin
    insert into tempdb values(@tempid)
    set @tempid = @tempid + 1
end

select tempdb.tempid from tempdb
left join MYDAT on tempdb.tempid = SUBSTRING(MYDAT.ID, 3, 3)
where 
SUBSTRING(MYDAT.ID, 3, 3) <> '' and
SUBSTRING(MYDAT.ID, 3, 3) <> '000'and
SUBSTRING(MYDAT.ID, 3, 3)  NOT LIKE '%[^0-9]%'

问题在于 where 子句不一定在 on 子句之前 执行 。 SQL 服务器可以重新安排操作。

我猜你真的想比较MYDAT.ID的前三个字符。这稍微简化了事情,因为您可以在下面的代码中使用 LEFT()。事实上,你的 where 条件看起来不对,所以我修正了它们。

最好的解决方案是try_convert():

select tempdb.tempid
from tempdb left join
     MYDAT
     on tempdb.tempid = try_convert(int, left(MYDAT.ID, 3) )
where MYDAT.ID <> '' and
      left(MYDAT.ID, 3) <> '000' and
      left(MYDAT.ID, 3) NOT LIKE '%[^0-9]%';

在 SQL Server 2012 之前的版本中,您可以使用 case 代替:

select tempdb.tempid
from tempdb left join
     MYDAT
     on tempdb.tempid = (case when left(MYDAT.ID, 1, 3) not like '%[^0-9]%')
                              then convert(int, left(MYDAT.ID, 3)
                         end)
where MYDAT.ID <> '' and
      left(MYDAT.ID, 3) <> '000' and
      left(MYDAT.ID, 3) NOT LIKE '%[^0-9]%';

case确实保证了求值顺序。

您确实说过 'missing numbers' 所以 tempdb 中不在 MYDAT 中的东西就是您所追求的?如果是,请参阅:http://rextester.com/HCB88714