SQL Server:我想创建一个函数,根据参数从字符串中删除特定字符。
例如:
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
由于
答案 0 :(得分: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 ║
╚═══════════════════╩══════════════╩════════════════╝
上述代码可以转换为用户定义的函数。如果您有更多记录,我建议创建内联表值函数而不是标量函数。
拆分字符串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
答案 1 :(得分: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
答案 2 :(得分: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='.'+@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)
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