Sql 如何提取美国邮政编码并检查范围

Sql 如何提取美国邮政编码并检查范围,sql,sql-server-2008,alias,Sql,Sql Server 2008,Alias,我有一个地址表,上面有美国和加拿大的邮政编码。在我们的系统中,我们根据邮政编码范围分配地区,因此我需要提取美国地址并检查它们是否在给定范围内。这些表如下所示: Key Postalcode --------------------------- 1 58230 2 49034-9731 3 98801 4 M5H 4E7 我运行select语句 SELECT

我有一个地址表,上面有美国和加拿大的邮政编码。在我们的系统中,我们根据邮政编码范围分配地区,因此我需要提取美国地址并检查它们是否在给定范围内。这些表如下所示:

Key             Postalcode
---------------------------
1               58230
2               49034-9731
3               98801
4               M5H 4E7
我运行select语句

SELECT 
    key, CONVERT(int, LEFT(LTRIM(RTRIM(Postalcode)),5)) AS pcode 
FROM 
    Table 
WHERE
    LEFT(Postalcode, 5) NOT LIKE '%[^0-9]%'
结果将按预期返回表

Key             Postalcode
--------------------------
1               58230
2               49034
3               98801
然后我包装别名并尝试检查范围

select 
    key, pcode 
from 
    (select 
         key, convert(int, LEFT(ltrim(rtrim(Postalcode)),5)) as pcode  
     from  
         Table 
     where 
         LEFT(Postalcode,5) not like '%[^0-9]%') x
 where 
     x.pcode between 58000 and 59000
SQL Server 2008返回此错误

Msg 245,第16级,状态1,第1行
将varchar值“M5H 4”转换为数据类型int时,转换失败


有人能告诉我发生了什么事吗?从别名中选择似乎正在扫描原始表,并遇到加拿大邮政编码。任何帮助都将不胜感激。

如果您需要
pcode
,请使用:

select key, pcode
from (select key,
             (case when postalcode like '[0-9][0-9][0-9][0-9][0-9]%'
                   then cast(left(postalcode, 5) as int)
              end) as pcode
      from t
     ) t
where t.pcode between 58000 and 59000;
但是,转换为int确实是不必要的。您只需使用:

select key, left(postalcode, 5)
from table t
where postalcode like '[0-9][0-9][0-9][0-9][0-9]%' and
      postalcode between '58000' and '59000';
将邮政编码视为字符串而不是数字更有意义


而且,代码不起作用的原因是SQL Server不能保证
select
where
中表达式的求值顺序。因此,它将
pcode
的计算推到过滤之前。从性能的角度来看,这是一件好事,但我认为这是一个错误。使用
case
(这确实保证了对其条件的评估顺序)很容易解决问题。

Hi@terry-h,您能提到您正在使用的数据库吗?这是显而易见的,但它将有助于任何未来的读者。谢天谢地,具体的情况是,您试图将一个不是数字的值转换为数字。之所以会发生这种情况,是因为您的select语句包含一个非数字的邮政编码,您正试图将其转换为整数。在一个单独的、有些不相关的注释中,您在处理整个邮政编码时要小心,特别是当数据开始扩展到北美以外的地区时,因为有些国家干脆不使用邮政编码(想到爱尔兰)。