25

I have a varchar(50) sql server column with data like this:

RawData
----------------------------
Washington 40 New Orleans 32
Detroit 27 St. Louis 23

I'm trying to parse out the data so I have something like this:

WinningTeam     WinningTeamScore      LosingTeam    LosingTeamScore
-----------     ----------------      ----------    ---------------
Washington      40                    New Orleans   32
Detroit         27                    St. Louis     23

I'm stuck. I was going to use charindex to find the first space, however some city names (St. Louis, New York, etc) have spaces in the names.

Is there a way to identify the position of the first number in a string?

Thanks

codingguy3000
  • 2,695
  • 15
  • 46
  • 74

6 Answers6

44

Is there a way to identify the position of the first number in a string?

Yes

SELECT PATINDEX('%[0-9]%','Washington 40 New Orleans 32')

PATINDEX returns 0 if the pattern can't be found or the 1 based index of the beginning of the match otherwise.

Martin Smith
  • 438,706
  • 87
  • 741
  • 845
16

You can use the PATINDEX function instead of CHARINDEX, here lies the documentation ;)

fnurglewitz
  • 2,097
  • 14
  • 21
5

Here is a very ugly implementation of PATINDEX() which returns the data in the multiple columns:

SELECT rtrim(substring(RawData, 1, PATINDEX('%[0-9]%', RawData) -1)) WinningTeam,
    ltrim(rtrim(substring(RawData, PATINDEX('%[0-9]%', RawData), 2))) WinningTeamScore,
    reverse(ltrim(rtrim(substring(reverse(SUBSTRING(RawData, 1, LEN(rawdata) - (PATINDEX('%[aA-zZ]%', REVERSE(rawData)) - PATINDEX('%[0-9]%', reverse(RawData))))), 1, PATINDEX('%[0-9]%', SUBSTRING(RawData, 1, LEN(rawdata) - (PATINDEX('%[aA-zZ]%', REVERSE(rawData)) - PATINDEX('%[0-9]%', reverse(RawData))))))))) LosingTeam,
    substring(reverse(RawData), PATINDEX('%[0-9]%', reverse(RawData)), (PATINDEX('%[aA-zZ]%', REVERSE(rawData)) - PATINDEX('%[0-9]%', reverse(RawData)))) LosingTeamScore
from yourtable

See SQL Fiddle with Demo

Taryn
  • 242,637
  • 56
  • 362
  • 405
4

Maybe a bit complicated but it works for what you need:

declare @test table(mytext varchar(50))

insert @test values('Washington 40 New Orleans 32')
insert @test values('Detroit 27 St. Louis 23')

select 
WinningTeam=SubString(mytext, 0,PatIndex('%[0-9.-]%', mytext)), 
WinningTeamScore=Left(SubString(mytext, PatIndex('%[0-9.-]%', mytext), 50),PatIndex('%[^0-9.-]%', SubString(mytext, PatIndex('%[0-9.-]%', mytext), 50) + 'X')-1),
LosingTeam=SubString(mytext, PatIndex('%[0-9.-]%', mytext)+3,PatIndex('%[0-9.-]%', mytext)), 
LosingTeamScore=reverse(Left(SubString(reverse(mytext), PatIndex('%[0-9.-]%', reverse(mytext)), 50),PatIndex('%[^0-9.-]%', SubString(reverse(mytext), PatIndex('%[0-9.-]%', reverse(mytext)), 50) + 'X')-1)) 
from @test

The query above works for scores under 100 points but you can modify it to deal with any number.

David Aleu
  • 3,922
  • 3
  • 27
  • 48
  • This is almost perfect. I just had to remove the "." from the pattern. So [0-9.-] was changed to [0-9-]. It works. Thanks a lot David!!!! – codingguy3000 Nov 14 '12 at 16:45
3

my query for selecting multi-didget numbers out of a url (ignore rows without a number and rows where the number is after the '?'

select 
    URL,
    substring(URL,PATINDEX ('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',URL),7) as id
from data 
where 
    PATINDEX ('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',URL)>0 
and PATINDEX ('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',URL)<charindex ('?',URL)
Andrew Hill
  • 1,921
  • 1
  • 25
  • 31
0
WITH CTE AS (
    SELECT 'Washington 40 New Orleans 32' as RawData
    UNION ALL
    SELECT 'Detroit 27 St. Louis 23'
), CTEGetFirsTeam as ( --Find first score and everything before it is first team name, everything after is second team
    SELECT SUBSTRING(c.RawData, 1, c.pos1Start - 1) as WinningTeam
         , CONVERT(int, SUBSTRING(c.RawData, c.pos1Start + 1, c.pos1End - c.pos1Start - 1)) as WinningTeamScore
         , SUBSTRING(c.RawData, c.pos1End + 1, LEN(c.RawData)) as SecondTeam
    FROM (
        SELECT b.*,
               pos1End = b.pos1Start + PATINDEX('% %', b.NewData)
        FROM ( 
            SELECT a.*, SUBSTRING(a.RawData, a.pos1Start + 1, LEN(a.RawData)) as NewData
            FROM (
                SELECT RawData, pos1Start = PATINDEX('% [0-9]%', RawData)
                FROM CTE
                ) a
            ) b
        ) c
) --Repeat for second team
SELECT c.WinningTeam, c.WinningTeamScore
    , SUBSTRING(c.RawData, 1, pos1Start - 1) as LosingTeam
    , CONVERT(int, SUBSTRING(c.RawData, pos1Start + 1, pos1End - pos1Start - 1)) as LosingTeamScore
FROM (
    SELECT b.*,
        pos1End = LEN(b.RawData) + 1
    FROM (
        SELECT a.*, SUBSTRING(a.RawData, a.pos1Start + 1, LEN(a.RawData)) as NewData
        FROM (
            SELECT WinningTeam, WinningTeamScore, SecondTeam as RawData, pos1Start = PATINDEX('% [0-9]%', SecondTeam)
            FROM CTEGetFirsTeam 
            ) a
        ) b
    ) c`
Glen
  • 802
  • 1
  • 11
  • 27