SQL Server Adventureworks Person.Person电话表

时间:2014-11-07 03:50:52

标签: sql-server-2012 adventureworks

我对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)有效?

谢谢,

Mark Brodie

1 个答案:

答案 0 :(得分:0)

我无法解释为什么数据可能会或可能不会成为拼写错误,但这是一个很好的示例和提示,以便始终仔细编写潜在的数据问题。

对于(2)vs(3),错误是由隐式转换引起的。在(2)和(3)中,通过使用n NOT IN (<subquery>),您隐式强制将子查询返回的元素转换为INT进行比较,错误消息是子查询中的元素不能全部转换为INT(就您的错误消息而言,关于以&#34; 1开头的电话号码(&#34;。

有趣的是为什么(3)有效但(2)没有。如果您将n NOT IN更改为CONVERT(VARCHAR(10), n),它们都可以正常运行。在SUBSTRING之后但在应用WHERE子句之前,Query(2)尝试对每个元素进行INT隐式转换,这就是生成错误的原因。在查询(3)中,让REPLACE首先修改执行(并且执行计划确认这一点),在结果集上发生对INT的隐式转换之前,应用WHERE中的LIKE。