- CREATE FUNCTION dbo.RemoveChars(@Input varchar(1000))
- RETURNS VARCHAR(1000)
- BEGIN
- DECLARE @pos INT
- SET @Pos = PATINDEX('%[^0-9]%',@Input)
- WHILE @Pos > 0
- BEGIN
- SET @Input = STUFF(@Input,@pos,1,'')
- SET @Pos = PATINDEX('%[^0-9]%',@Input)
- END
- RETURN @Input
- END
- DECLARE @test TABLE(x VARCHAR(20));
- INSERT INTO @test (x)
- SELECT '+91 (876) 098 6789' UNION ALL
- SELECT '1-567-987-7655' UNION ALL
- SELECT 'FR5-5105';
- WITH
- Num1 (n) AS (SELECT 1 UNION ALL SELECT 1),
- Num2 (n) AS (SELECT 1 FROM Num1 AS X, Num1 AS Y),
- Num3 (n) AS (SELECT 1 FROM Num2 AS X, Num2 AS Y),
- Num4 (n) AS (SELECT 1 FROM Num3 AS X, Num3 AS Y),
- Nums (n) AS (SELECT ROW_NUMBER() OVER(ORDER BY n) FROM Num4),
- Cleaner AS (
- SELECT x
- , (SELECT
- CASE
- WHEN SUBSTRING(x, n, 1) NOT LIKE '[^0-9]'
- THEN SUBSTRING(x, n, 1)
- ELSE ''
- END + ''
- FROM Nums
- WHERE n <= LEN(x)
- FOR XML PATH('')) AS x_clean
- FROM @test)
- SELECT x, x_clean
- FROM Cleaner;
- /*
- x x_clean
- -------------------- -------------
- +91 (876) 098 6789 918760986789
- 1-567-987-7655 15679877655
- FR5-5105 55105
- */
На мой взгляд просто замечательный подход, но что нам делать если такая задача будет повторяться?! Не переписывать же под каждую задачу этот кусок (мне надо было 8 полей очистить в одном единственном запросе)
И тут на помощь приходят табличные функции
- CREATE FUNCTION fnt_RemoveNonNumericChars (@x varchar(50))
- RETURN TABLE
- AS
- RETURN (
- WITH
- Num1 (n) AS (SELECT 1 UNION ALL SELECT 1),
- Num2 (n) AS (SELECT 1 FROM Num1 AS X, Num1 AS Y),
- Num3 (n) AS (SELECT 1 FROM Num2 AS X, Num2 AS Y),
- Num4 (n) AS (SELECT 1 FROM Num3 AS X, Num3 AS Y),
- Nums (n) AS (SELECT ROW_NUMBER() OVER(ORDER BY n) FROM Num4),
- Cleaner AS (
- SELECT @x [x]
- , (SELECT
- CASE
- WHEN SUBSTRING(@x, n, 1) NOT LIKE '[^0-9]'
- THEN SUBSTRING(@x, n, 1)
- ELSE ''
- END + ''
- FROM Nums
- WHERE n <= LEN(@x)
- FOR XML PATH('')) AS x_clean
- )
- SELECT x, x_clean
- FROM Cleaner;
- )
И вот собственно вариант использования:
- DECLARE @test TABLE(x VARCHAR(20));
- INSERT INTO @test (x)
- SELECT '+91 (876) 098 6789' UNION ALL
- SELECT '1-567-987-7655' UNION ALL
- SELECT 'FR5-5105';
- SELECT
- t.x
- , vv.x
- , vv.x_clean
- FROM @test t
- CROSS APPLY fnt_RemoveNonNumericChars(t.x) vv
И результат выполнения:
- t.x vv.x vv.x_clean
- -------------------- -------------------- -------------
- +91 (876) 098 6789 +91 (876) 098 6789 918760986789
- 1-567-987-7655 1-567-987-7655 15679877655
- FR5-5105 FR5-5105 55105
ВАЖНО!!! Если будете использовать вариант с XML имейте в виду, порядок цифр может перемешаться, наткнулся на эту проблему буквально на следующий день.
В принципе мне не очень нравится текущий вариант нумерации, но это уже лирика, ее легко можно поменять, это позволит сэкономить еще несколько тактов, особенно на больших числах.
Комментариев нет:
Отправить комментарий