Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have the following code to split an address string in T-SQL. Excepting the unit number, which is already in its own field, it would affect too much of the application to split the address into different database fields. It's a bit of a long story, but it's also not possible to make it a parameterized query, or to write the equivalent application code in C#. Still, I'm curious if anyone can think of any edge case that would put things into the wrong fields.

The only case I've come across is "East End Ave", but even the US Postal Service suggests incorrectly parsing 'East' as a directional (for consistency) (reference: very long pdf, search for 'directional', or go to page 233).

I'm only worried about Canadian and American addresses, but in Canada, French-style street types before the street name are fair game (e.g. 'Rue Montreal').

StreetType and StreetDirection are tables which contain street types and street directions, as TypeName/TypeAbbr and DirectionName/DirectionType pairs respectively - I can post the values I've been using there if anyone's curious, but the StreetType is quite long. StreetDirection also includes French directions ('ouest', 'nord', 'sud', 'est', etc.), as well as their equivalents of 'northeast', 'northwest', etc.

DECLARE @CivicNum AS NVARCHAR(10) = ''
DECLARE @Predir AS NVARCHAR(10) = ''
DECLARE @Name AS NVARCHAR(100) = ''
DECLARE @Type AS NVARCHAR(15) = ''
DECLARE @FrenchType AS NVARCHAR(15) = ''
DECLARE @Postdir AS NVARCHAR(10) = ''

SET @Name = '123 Fake St.'

SET @CivicNum = SUBSTRING(@Name, 1, 1)

IF ISNUMERIC(@CivicNum) = 1
  BEGIN
    -- will assume a civic number
    DECLARE @LastSpace AS INTEGER
    DECLARE @NextSpace AS INTEGER

    DECLARE @Temp as VARCHAR(15)

    -- first token - civic number
    SET @LastSpace = 1
    SET @NextSpace = CHARINDEX(' ', @Name)
    SET @CivicNum = SUBSTRING(@Name, 1, @NextSpace)

    -- next token - check for fraction
    SET @LastSpace = @NextSpace + 1
    SET @NextSpace = CHARINDEX(' ', @Name, @LastSpace)

    SET @Temp = SUBSTRING(@Name, @LastSpace, @NextSpace - @LastSpace)
    IF CHARINDEX('\\', @Temp) > 0 OR CHARINDEX ('/', @Temp) > 0
      SET @CivicNum = @CivicNum + ' ' + @Temp
    ELSE
      SET @NextSpace = @LastSpace

    -- reverse to extract type, direction from right
    SET @Name = REVERSE(SUBSTRING(@Name, @NextSpace, LEN(@Name)))

    -- last token - post direction
    SET @LastSpace = 1
    SET @NextSpace = CHARINDEX(' ', @Name)    
    SET @Temp = RTRIM(LTRIM(REVERSE(SUBSTRING(@Name, 1, @NextSpace))))
    IF SUBSTRING(@Temp, LEN(@Temp), 1) = '.' -- strip period
      SET @Temp = SUBSTRING(@Temp, 1, LEN(@Temp) - 1)

    SELECT @PostDir=DirectionAbbr FROM StreetDirection WHERE UPPER(DirectionName) LIKE UPPER(@Temp)
    IF NOT (@PostDir LIKE @Temp) -- try abbreviation
      SELECT @PostDir=DirectionAbbr FROM StreetDirection WHERE UPPER(DirectionAbbr) LIKE UPPER(@Temp)

    -- get next token if there was a postdir
    IF NOT (@PostDir LIKE '') 
      BEGIN
       SET @LastSpace = @NextSpace + 1
       SET @NextSpace = CHARINDEX(' ', @Name, @LastSpace + 1)
       SET @Temp = RTRIM(LTRIM(REVERSE(SUBSTRING(@Name, @LastSpace, @NextSpace - @LastSpace))))
       IF SUBSTRING(@Temp, LEN(@Temp), 1) = '.' -- strip period 
          SET @Temp = SUBSTRING(@Temp, 1, LEN(@Temp) - 1)
      END

    -- next-to-last token - street type      
    SELECT @Type=TypeName FROM StreetType WHERE UPPER(TypeName) LIKE UPPER(@Temp)
    IF NOT (@Type LIKE @Temp) -- try abbreviation
      SELECT @Type=TypeName FROM StreetType WHERE UPPER(TypeAbbr) LIKE UPPER(@Temp)

    -- reverse address again to check for pre-dir and french street type
    IF NOT (@Type LIKE '')
      SET @LastSpace = @NextSpace + 1

    SET @Name = RTRIM(LTRIM(REVERSE(SUBSTRING(@Name, @LastSpace, LEN(@Name)))))

    -- next token - pre-direction
    SET @LastSpace = 1
    SET @NextSpace = CHARINDEX(' ', @Name)
    SET @Temp = RTRIM(LTRIM(SUBSTRING(@Name, 1, @NextSpace)))
    IF SUBSTRING(@Temp, LEN(@Temp), 1) = '.' -- strip period
      SET @Temp = SUBSTRING(@Temp, 1, LEN(@Temp) - 1)

    SELECT @PreDir=DirectionAbbr FROM StreetDirection WHERE UPPER(DirectionName) LIKE UPPER(@Temp)
    IF NOT (@PreDir LIKE @Temp) -- try abbreviation
      SELECT @PreDir=DirectionAbbr FROM StreetDirection WHERE UPPER(DirectionAbbr) LIKE UPPER(@Temp)    

    -- next token - French street type
    IF NOT (@PreDir LIKE '') 
      BEGIN
       SET @LastSpace = @NextSpace + 1
       SET @NextSpace = CHARINDEX(' ', @Name, @LastSpace + 1)
       SET @Temp = RTRIM(LTRIM(SUBSTRING(@Name, @LastSpace, LEN(@Name))))
       IF SUBSTRING(@Temp, LEN(@Temp), 1) = '.' -- strip period 
          SET @Temp = SUBSTRING(@Temp, 1, LEN(@Temp) - 1)
      END

    -- check for French street type before address
    IF (@Type LIKE '') -- only if not already found (prefer English type)
      BEGIN
        SELECT @FrenchType=TypeName FROM StreetType WHERE UPPER(TypeName) LIKE UPPER(@Temp)
        IF NOT (@FrenchType LIKE @Temp) -- try abbreviation
          SELECT @FrenchType=TypeName FROM StreetType WHERE UPPER(TypeAbbr) LIKE UPPER(@Temp)
      END

    IF NOT (@FrenchType Like '')
      BEGIN
        SET @LastSpace = @NextSpace
        SET @Type = @FrenchType
      END

    -- rest is street name
    SET @Name = SUBSTRING(@Name, @LastSpace, LEN(@Name))

    SELECT @CivicNum AS CivicNum, @Name AS Address, @Type AS StreetType, @PostDir + @PreDir AS Direction
ELSE
    SELECT @CivicNum AS CivicNum, @Name AS Address, @Type AS StreetType, @PostDir + @PreDir AS Direction

If nothing else, I hope this is a snippet of code someone finds handy!

share|improve this question
1  
This is probably covered by your French cases but I wanted to point out that in some American cities (San Diego) Spanish names are numerous. Avenida Montuosa, Via San Marco, Caminito Suenos, etc. And you may have spanish directionals as well. "Paseo del Pueblo Sur". So it is not just French names that you need to account for. – nickles80 Aug 23 '12 at 21:32
Interesting! We may not actually be required to fill out American addresses in this same way, but even so it should be fairly simple to add the Spanish types and directionals. – Hannele Aug 24 '12 at 13:03
I can't follow the code, but just wanted to point out that not all US addresses have a "street type". My parents once had an address that was something like 20 Fairbanks. That's it, no street, no ave, no blvd, nothing, just Fairbanks. – Donald.McLean Aug 30 '12 at 4:30
@Donald.McLean Perhaps the most confusing aspect is that I couldn't find a way to find the last occurrence of a character, nor is there a way to split a string into tokens by delimiter. So, I was left to keeping track of the last space, and reversing the whole string to take tokens from the right hand side. Thanks for the comment, though! I think this should still work without a street type. – Hannele Aug 30 '12 at 17:12

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.