获取两个连续大写字符的索引

时间:2013-12-23 16:14:39

标签: sql sql-server collation string-parsing

我正在尝试将city/state/zip字段分为城市,州和邮政编码。通常情况下,我会使用charindex ','获取城市和州,isnumericright()执行此操作。

这适用于zip,但我现在使用的数据中的大多数行都没有逗号City ST Zip。有没有办法识别两个大写字符的索引?

如果没有,是否有人比单独检查每个州的案例陈述有更好的想法?

编辑:我发现PATINDEX / COLLATE选项可以间歇性地工作。请参阅下面的答案。

5 个答案:

答案 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个Collat​​ions首先排列大写)。在区分大小写的排序规则中执行此操作时,仅将所有A条目组合在一起,与a条目分开,而在 in 敏感排序中,它们将是混合

但是如果你单独指定每个字母(因此不使用范围),那么它将按预期工作:

PATINDEX(N'%[ABCDEFGHIJKLMNOPQRSTUVWXYZ][ABCDEFGHIJKLMNOPQRSTUVWXYZ]%',
     [CityStZip] COLLATE Latin1_General_100_CS_AS)

PATINDEXLIKE(两者都允许单个字符类[A-Z])以这种方式工作的原因是[start-end]语法是不是正则表达式。许多人声称由于支持此语法,PATINDEXLIKE支持“限制”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