2016-12-10 5 views
-2

SQL Server: Я хотел бы создать функцию, которая удаляет определенные символы из строки на основе параметров.SQL Server Удаление определенных символов из строки

  • параметр1 является исходная строка
  • параметр2 это символы хотят, чтобы удалены из исходной строки

Например:

call MyRemoveFunc('32.87.65.54.89', '87.65') -- this will return '32.54.89' 
call MyRemoveFunc('11.23.45', '23') -- this will return '11.45' 
call MyRemoveFunc('14.99.16.84', '84.14') -- this will return '99.16' 
call MyRemoveFunc('11.23.45.65.31.90', '23') -- this will return 11.45.65.31.90 

call MyRemoveFunc('34.35.36', '35') -- this will return 34.36 

call MyRemoveFunc('34.35.36.76.44.22', '35') -- this will return 34.36.76.44.22 

call MyRemoveFunc('34', '34') -- this will return blank 

call MyRemoveFunc('45.23.11', '45.11') -- this will return 23 

Благодарности

+1

Пожалуйста рассмотрю, как написать хороший вопрос [здесь] (Http: //stackoverflow.com/help/how-to-ask)! После подробностей на этой странице, редактируя этот вопрос, вы можете получить ответ, который вы ищете! –

+0

Не могли бы вы объяснить, как получить результат для 'call MyRemoveFunc ('34 .35.36.76.44.22 ',' 35 ') - это вернет 34.36' – Squirrel

+0

какую версию сервера sql вы используете? – DarkKnight

ответ

1

Вот один из способов, используя Recursive CTE и Split string функция

;WITH data 
    AS (SELECT org_string, 
       replace_with, 
       cs.Item, 
       cs.ItemNumber 
     FROM (VALUES ('32.87.65.54.89','87.65'), 
         ('11.23.45','23'), 
         ('14.99.16.84','84.14'), 
         ('11.23.45.65.31.90','23'), 
         ('34.35.36','35'), 
         ('34.35.36.76.44.22','35'), 
         ('34','34'), 
         ('45.23.11','45.11')) tc (org_string, replace_with) 
       CROSS apply [Delimitedsplit8k](replace_with, '.') cs), 
    cte 
    AS (SELECT org_string, 
       replace_with, 
       Item, 
       Replace('.' + org_string, + '.' + Item, '') AS result, 
       ItemNumber 
     FROM data 
     WHERE ItemNumber = 1 
     UNION ALL 
     SELECT d.org_string, 
       d.replace_with, 
       d.Item, 
       CASE 
        WHEN LEFT(Replace('.' + result, '.' + d.Item, ''), 1) = '.' THEN Stuff(Replace('.' + result, '.' + d.Item, ''), 1, 1, '') 
        ELSE Replace('.' + result, '.' + d.Item, '') 
       END, 
       d.ItemNumber 
     FROM cte c 
       JOIN data d 
        ON c.org_string = d.org_string 
        AND d.ItemNumber = c.ItemNumber + 1) 
SELECT TOP 1 WITH ties org_string, 
         replace_with, 
         result = Isnull(Stuff(result, 1, 1, ''), '') 
FROM cte 
ORDER BY Row_number()OVER(partition BY org_string ORDER BY ItemNumber DESC) 

Результат:

╔═══════════════════╦══════════════╦════════════════╗ 
║ org_string  ║ replace_with ║  result  ║ 
╠═══════════════════╬══════════════╬════════════════╣ 
║ 11.23.45   ║ 23   ║ 11.45   ║ 
║ 11.23.45.65.31.90 ║ 23   ║ 11.45.65.31.90 ║ 
║ 14.99.16.84  ║ 84.14  ║ 99.16   ║ 
║ 34    ║ 34   ║    ║ 
║ 34.35.36   ║ 35   ║ 34.36   ║ 
║ 34.35.36.76.44.22 ║ 35   ║ 34.36.76.44.22 ║ 
║ 45.23.11   ║ 45.11  ║ 23    ║ 
║ 32.87.65.54.89 ║ 87.65  ║ 32.54.89  ║ 
╚═══════════════════╩══════════════╩════════════════╝ 

Приведенный выше код может быть преобразован в пользовательской функции. Я предлагаю создать функцию Value Inline Table вместо функции Scalar, если у вас больше записей.

Split код строки Функция перешедших из http://www.sqlservercentral.com/articles/Tally+Table/72993/

CREATE FUNCTION [dbo].[DelimitedSplit8K] 

     (@pString VARCHAR(8000), @pDelimiter CHAR(1)) 
RETURNS TABLE WITH SCHEMABINDING AS 
RETURN 
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000... 
    -- enough to cover NVARCHAR(4000) 
    WITH E1(N) AS (
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
       ),       --10E+1 or 10 rows 
     E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
     E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front 
        -- for both a performance gain and prevention of accidental "overruns" 
       SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
       ), 
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter) 
       SELECT 1 UNION ALL 
       SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter 
       ), 
cteLen(N1,L1) AS(--==== Return start and length (for use in substring) 
       SELECT s.N1, 
         ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000) 
        FROM cteStart s 
       ) 
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found. 
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1), 
     Item  = SUBSTRING(@pString, l.N1, l.L1) 
    FROM cteLen l 
; 
GO 
+0

это не простая замена. см. 'call MyRemoveFunc ('14 .99.16.84 ',' 84.14 ') - это вернет '99 .16'' – Squirrel

+0

@Squirrel - обновлено ... –

+0

@Prdp выберите dbo.Udf_string_replace ('45 .23.11', '45.11') - return 11.45.23 это неверно corrct is return '23' – Bas

0

Вы могли бы попробовать это ..

CREATE FUNCTION StringSpecialReplace(@TargetString VARCHAR(1000), 
            @InputString VARCHAR(1000)) 
returns VARCHAR(1000) 
AS 
    BEGIN 

    declare @result as varchar(1000) 

    ;with CTE1 AS 
    (
     SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Certs 
     FROM (SELECT CAST('<XMLRoot><RowData>' + REPLACE(@TargetString,'.','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x)t 
     CROSS APPLY x.nodes('/XMLRoot/RowData')m(n) 
    ), 
    CTE2 AS 
    (
     SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Certs 
     FROM (SELECT CAST('<XMLRoot><RowData>' + REPLACE(@InputString,'.','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x)t 
     CROSS APPLY x.nodes('/XMLRoot/RowData')m(n) 
    ) 

    SELECT 
     @Result = CASE 
      WHEN @Result IS NULL 
      THEN certs 
      ELSE @Result + '.' + certs 
     END 
    FROM CTE1 where certs not in (select certs from CTE2) 

    return @Result 
END 
+0

спасибо @DarkKnight .... i попытаюсь . и воспроизведение – Bas

0
CREATE FUNCTION MyRemoveFunc (
      @OrigString VARCHAR(8000), 
      @RemovedString VARCHAR(max) 
      ) 
    RETURNS varchar(max) 
    BEGIN 

      DECLARE @xml XML 
      SET @xml='<n>'+REPLACE(@RemovedString,'.','</n><n>')+'</n>' 
      SET @OrigString='.'[email protected]+'.' 
      SELECT @OrigString=REPLACE(@OrigString,'.'+s.b.value('.','varchar(200)')+'.','.') 
      FROM @xml.nodes('n')s(b) 
      RETURN CASE WHEN LEN(@OrigString)>2 THEN SUBSTRING(@OrigString,2,LEN(@OrigString)-2) ELSE '' END 

    END 


    SELECT t.*,dbo.MyRemoveFunc(t.o,t.r) 
    FROM (VALUES ('32.87.65.54.89','87.65'), 
          ('11.23.45','23'), 
          ('14.99.16.84','84.14'), 
          ('11.23.45.65.31.90','23'), 
          ('34.35.36','35'), 
          ('34.35.36.76.44.22','35'), 
          ('34','34'), 
          ('45.23.11','45.11')) t (o, r) 
 
o     r  
----------------- ----- ------------------------- 
32.87.65.54.89 87.65 32.54.89 
11.23.45   23 11.45 
14.99.16.84  84.14 99.16 
11.23.45.65.31.90 23 11.45.65.31.90 
34.35.36   35 34.36 
34.35.36.76.44.22 35 34.36.76.44.22 
34    34  
45.23.11   45.11 23 
Смежные вопросы