我正在尝试将city/state/zip
字段分为城市,州和邮政编码。通常情况下,我会使用charindex
','
获取城市和州,isnumeric
和right()
执行此操作。
这适用于zip,但我现在使用的数据中的大多数行都没有逗号City ST Zip
。有没有办法识别两个大写字符的索引?
如果没有,是否有人比单独检查每个州的案例陈述有更好的想法?
编辑:我发现PATINDEX / COLLATE选项可以间歇性地工作。请参阅下面的答案。
答案 0 :(得分:4)
PATINDEX应该适合你:
PATINDEX('% [A-Z][A-Z] %', A COLLATE Latin1_general_cs_as)
所以你的全部摘录将是:
WITH CTE AS
( SELECT i = PATINDEX('% [A-Z][A-Z] %', A COLLATE Latin1_general_cs_as) + 1,
A
FROM (VALUES
('City ST Zip'),
('Another City ST Zip'),
('City, with comma ST Zip')
) t (A)
)
SELECT City = LEFT(A, i - 2),
State = SUBSTRING(A, i, 2),
Zip = SUBSTRING(A, i + 3, LEN(A))
FROM CTE;
<强> Example on SQL Fiddle 强>
答案 1 :(得分:2)
如果您在字符串的末尾有邮政编码和状态,那么这可能有效:
select right(address, 5) as zip,
left(right(address, 8), 2) as state,
left(address, len(address) - 9) as city
您可以从地址中删除逗号和双重空格。
答案 2 :(得分:2)
PATINDEX
似乎间歇性工作的原因是您不能使用字符范围(即A-Z
)来完成区分大小写的搜索,即使使用区分大小写的排序规则也是如此。问题是字符范围像排序一样工作,区分大小写的排序将大写字母与它们的小写等价物分组,就像它在字典中排序一样。范围排序实际上是:a,A,b,B,c,C,d,D等。或者,根据整理,它可能是:A,a,B,b,C,c,D,d等(有31个Collations首先排列大写)。在区分大小写的排序规则中执行此操作时,仅将所有A
条目组合在一起,与a
条目分开,而在 in 敏感排序中,它们将是混合
但是如果你单独指定每个字母(因此不使用范围),那么它将按预期工作:
PATINDEX(N'%[ABCDEFGHIJKLMNOPQRSTUVWXYZ][ABCDEFGHIJKLMNOPQRSTUVWXYZ]%',
[CityStZip] COLLATE Latin1_General_100_CS_AS)
PATINDEX
和LIKE
(两者都允许单个字符类[A-Z]
)以这种方式工作的原因是[start-end]
语法是不是正则表达式。许多人声称由于支持此语法,PATINDEX
和LIKE
支持“限制”RegEx,但事实并非如此。它只是一个与RegEx非常相似(且容易混淆的)语法,其中[A-Z]
通常不包含任何小写匹配。
当然,如果您保证只搜索AZ的美英字母,那么二进制整理(即以_BIN2
结尾;不要使用以_BIN
结尾的字母因为自从引入SQL Server 2005以来它们已被弃用,我认为应该可以工作。
PATINDEX(N'%[A-Z][A-Z]%', [CityStZip] COLLATE Latin1_General_100_BIN2)
有关区分大小写匹配的更多详细信息,尤其是有关包含Unicode / NVARCHAR数据的详细信息,请参阅我在DBA.StackExchange上的相关答案:
How to find values with multiple consecutive upper case characters
答案 3 :(得分:0)
如果你有一个状态表(你应该)和一列缩写你可以这样做:
SELECT a.* FROM Addresses a
INNER JOIN States s ON
a.CityStateZip Like '% ' + s.UpperCaseAbbreviation + ' %' --space on either side of abbreviation
您可以将其用于逗号和空格:
SELECT a.* FROM Addresses a
INNER JOIN States s ON
Replace(a.CityStateZip, ',' , ' ') Like '% ' + s.UpperCaseAbbreviation + ' %'
答案 4 :(得分:0)
我发现PATINDEX / COLLATE选项可以间歇性地工作。这是我最终做的事情:
--get rid of the sparsely used commas
--get rid of the duplicate spaces
update MyTable set
CityStZip=
replace(
replace(
replace(CityStZip,' ',' '),
' ',' '),
',','')
select
--check if state and zip are there and then grab the city
case when isNumeric(right(CityStZip,1))=1
then left(CityStZip,len(CityStZip)-charindex(' ',reverse(CityStZip),
charindex(' ',reverse(CityStZip))+1)+1)
--no zip. check for state
when left(right(CityStZip,3),1) = ' '
then left(CityStZip,len(CityStZip)-charIndex(' ',reverse(CityStZip)))
else CityStZip
end as City,
--check if zip is there and then grab the city
case when isNumeric(right(CityStZip,1))=1
then substring(CityStZip,
len(CityStZip)-charindex(' ',reverse(CityStZip),
charindex(' ',reverse(CityStZip))+1)+2,
2)
--no zip. check if 3rd to last char is a space and grab the last two chars
when left(right(CityStZip,3),1) = ' '
then right(CityStZip,2)
end as [State],
--grab everything after the last space if the last character is numeric
case when isNumeric(right(CityStZip,1))=1
then substring(CityStZip,
len(CityStZip)-charindex(' ',reverse(CityStZip))+1,
charindex(' ',reverse(CityStZip)))
end as Zip
from MyTable