我对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
答案 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。