0

我有一个关于 AdventureWorks2012 中的 Person.PersonPhone 表的问题,还有一个关于 SQL 的相关问题。

首先,表格中有一个显示为 55-2555-0100 的电话号码,这似乎是一个错字;据推测,它的目的是 552-555-0100,这将与其他电话号码的模式相匹配。我想知道是否有人可以确认这是一个错误。

其次,假设我们要确定哪些 3 位数的美国区号没有出现在 PhoneNumber 列中。一种方法是使用 Itzik Ben-Gan 的 TSQL2012 数据库中的 dbo.Nums 表,该表有一列 n,包含从 1 到 100,000 的整数。因此,例如,以下查询有效:

(1) SELECT n FROM dbo.Nums WHERE n >= 100 AND n < 1000 AND n NOT IN (SELECT SUBSTRING(P.PhoneNumber, 1, 3) FROM Person.PersonPhone AS P WHERE SUBSTRING(P.Phonenumber, 1, 3) LIKE '[1-9][0-9][0-9]');

但是,以下查询失败:

(2) SELECT n FROM dbo.Nums WHERE n >= 100 AND n < 1000 AND n NOT IN (SELECT SUBSTRING(P.PhoneNumber, 1, 3) FROM Person.PersonPhone AS P WHERE P.PhoneNumber LIKE '[1-9][0-9][0-9]%');

错误是“将 nvarchar 值 '1 (' 转换为数据类型 int 时转换失败。”

表格中有“1 (11) xxx”形式的电话号码,在本练习中应将其忽略。显然,它试图将 dbo.Nums 中的 n 与这些进行比较,即使子查询将它们排除在外。((2)中的子查询单独执行时,结果与(1)中的子查询完全相同)。

更奇怪的是,如果 (2) 通过做一些没有效果的事情来修改(例如在每个 PhoneNumber 中用空字符串替换空字符串),查询会突然起作用:

(3) SELECT n FROM dbo.Nums WHERE n >= 100 AND n < 1000 AND n NOT IN (SELECT SUBSTRING(REPLACE(P.PhoneNumber, '', ''), 1, 3) FROM Person.PersonPhone AS P WHERE P.PhoneNumber LIKE '[1-9][0-9][0-9]%');

那么为什么(2)失败但(3)有效?

谢谢,

马克布罗迪

4

1 回答 1

0

我无法解释为什么数据可能是错字也可能不是错字,但它是一个很好的示例,并提醒您始终仔细规划潜在的数据问题。

至于(2)与(3),错误是由于隐式转换。在 (2) 和 (3) 中,通过使用n NOT IN (<subquery>),您隐式强制将子查询返回的元素转换为 INT 进行比较,并且错误消息是子查询中的元素不能全部转换为一个 INT(如您关于以“1(”开头的电话号码的错误消息)的情况。

有趣的是为什么(3)有效但(2)无效。如果您更改n NOT INCONVERT(VARCHAR(10), n). 查询 (2) 在 SUBSTRING 之后但在 WHERE 子句应用之前尝试将每个元素隐式转换为 INT,这就是产生错误的原因。在查询 (3) 中,让 REPLACE 首先修改执行(并且执行计划确认这一点),即在结果集上发生到 INT 的隐式转换之前应用 WHERE 中的 LIKE。

于 2014-11-07T04:28:45.030 回答