Использование PATINDEX для поиска шаблонов различной длины в T-SQL - PullRequest
9 голосов
/ 19 марта 2012

Я хочу вытащить поплавки из некоторых varchars, используя PATINDEX (), чтобы определить их. Я знаю, что в каждой строке varchar меня интересует только первый существующий тип float, но он может иметь разную длину.

, например

'some text 456.09 other text'
'even more text 98273.453 la la la'

Я бы обычно сопоставлял их с регулярным выражением

  "[0-9]+[.][0-9]+"

Однако я не могу найти эквивалент для оператора +, который принимает PATINDEX. Таким образом, они должны быть сопоставлены (соответственно) с:

'[0-9][0-9][0-9].[0-9][0-9]' and '[0-9][0-9][0-9][0-9][0-9].[0-9][0-9][0-9]' 

Есть ли способ сопоставить оба этих примера varchars с одним допустимым шаблоном PATINDEX?

Ответы [ 6 ]

12 голосов
/ 20 марта 2012

Я писал об этом некоторое время назад. Извлечение чисел с помощью сервера SQL

Declare @Temp Table(Data VarChar(100))

Insert Into @Temp Values('some text 456.09 other text')
Insert Into @Temp Values('even more text 98273.453 la la la')
Insert Into @Temp Values('There are no numbers in this one')

Select Left(
             SubString(Data, PatIndex('%[0-9.-]%', Data), 8000),
             PatIndex('%[^0-9.-]%', SubString(Data, PatIndex('%[0-9.-]%', Data), 8000) + 'X')-1)
From   @Temp
2 голосов
/ 19 марта 2012

Подстановочные знаки.

SELECT PATINDEX('%[0-9]%[0-9].[0-9]%[0-9]%','some text 456.09 other text')
SELECT PATINDEX('%[0-9]%[0-9].[0-9]%[0-9]%','even more text 98273.453 la la la')
1 голос
/ 20 марта 2012

Должен быть проверен на надежность (например, если у вас есть только int), но это просто для того, чтобы вы встали на путь:

if exists (select routine_name from information_schema.routines where routine_name = 'GetFirstFloat')
    drop function GetFirstFloat
go

create function GetFirstFloat (@string varchar(max))
returns float
as
begin
    declare @float varchar(max)
    declare @pos int

    select @pos = patindex('%[0-9]%', @string)
    select @float = ''

    while isnumeric(substring(@string, @pos, 1)) = 1
    begin
        select @float = @float + substring(@string, @pos, 1)
        select @pos = @pos + 1
    end

    return cast(@float as float)
end
go


select dbo.GetFirstFloat('this is a string containing pi 3.14159216 and another non float 3 followed by a new fload 5.41 and that''s it')
select dbo.GetFirstFloat('this is a string with no float')
select dbo.GetFirstFloat('this is another string with an int 3')
1 голос
/ 19 марта 2012

Да, вам нужно связаться с clr, чтобы получить поддержку регулярных выражений.Но если PATINDEX не делает то, что вам нужно, регулярное выражение было разработано именно для этого.

http://msdn.microsoft.com/en-us/magazine/cc163473.aspx

0 голосов
/ 19 марта 2012

Учитывая, что длина шаблона будет различной, у вас не будет проблем с настройкой работы с PATINDEX. Есть еще один пост, который я написал , который я изменил, чтобы выполнить то, что вы пытаетесь сделать здесь.Будет ли это работать для вас?

CREATE TABLE #nums (n INT)
DECLARE @i INT 
SET @i = 1
WHILE @i < 8000 
BEGIN
    INSERT #nums VALUES(@i)
    SET @i = @i + 1
END

CREATE TABLE #tmp (
  id INT IDENTITY(1,1) not null,
  words VARCHAR(MAX) null
)

INSERT INTO #tmp
VALUES('I''m looking for a number, regardless of length, even 23.258 long'),('Maybe even pi which roughly 3.14159265358,'),('or possibly something else that isn''t a number')

UPDATE #tmp SET words = REPLACE(words, ',',' ')

;WITH CTE AS (SELECT ROW_NUMBER() OVER (ORDER BY ID) AS rownum, ID, NULLIF(SUBSTRING(' ' + words + ' ' , n , CHARINDEX(' ' , ' ' + words + ' ' , n) - n) , '') AS word
    FROM #nums, #tmp
    WHERE ID <= LEN(' ' + words + ' ') AND SUBSTRING(' ' + words + ' ' , n - 1, 1) = ' ' 
    AND CHARINDEX(' ' , ' ' + words + ' ' , n) - n > 0),
    ids AS (SELECT ID, MIN(rownum) AS rownum FROM CTE WHERE ISNUMERIC(word) = 1 GROUP BY id)
SELECT CTE.rownum, cte.id, cte.word
FROM CTE, ids WHERE cte.id = ids.id AND cte.rownum = ids.rownum

Объяснение и происхождение кода более подробно описано в оригинальном посте

0 голосов
/ 19 марта 2012

PATINDEX не достаточно мощный, чтобы сделать это.Вы должны использовать регулярные выражения.

SQL Server поддерживает регулярные выражения начиная с SQL Server 2005.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...