【问题标题】:SQL Server Remove some specific characters from stringSQL Server 从字符串中删除某些特定字符
【发布时间】:2017-04-25 13:53:35
【问题描述】:

SQL Server:我想创建一个函数,根据参数从字符串中删除特定字符。

  • parameter1 是原始字符串
  • parameter2 是要从原始字符串中删除的字符

例如:

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

谢谢

【问题讨论】:

  • 请复习如何写一个好问题here!通过编辑此问题遵循该页面上的详细信息可能会帮助您获得所需的答案!
  • 你能解释一下如何获得call MyRemoveFunc('34.35.36.76.44.22','35' ) -- this will return 34.36的结果
  • 你用的是什么版本的sql server?
  • sql server 2008
  • 他的第一个也没有……骗过我一次,真丢人,

标签: sql sql-server tsql replace


【解决方案1】:

这是使用Recursive CTESplit 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       ║
╚═══════════════════╩══════════════╩════════════════╝

上面的代码可以转换为用户定义的函数。如果您有更多记录,我会建议创建内联表值函数而不是标量函数。

拆分字符串引用自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

【讨论】:

  • 这不是一个简单的替换。见call MyRemoveFunc('14.99.16.84','84.14' ) -- this will return '99.16'
  • @Prdp select dbo.Udf_string_replace('45.23.11','45.11') -- return 11.45.23 这是错误的,正确的是 return '23'
  • @Bas - 更新检查现在.. 如果你想把它转换成函数,那么回复就可以了
【解决方案2】:

你可以试试这个..

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

【讨论】:

    【解决方案3】:
        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='.'+@OrigString+'.'
                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)
    
    要么 ----------------- ----- ------------- 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-03
      • 1970-01-01
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多