我有以下测试字符串显示在我的表格列中。
<B99_9>TEST</B99_9><LastDay>TEST</LastDay>
我想删除特定标记之间的值。例如:
REPLACE( <B99_9>TEST</B99_9><LastDay>TEST</LastDay>, <B99_9>TEST</B99_9>, <B99_9></B99_9> )
这应该给出以下输出:
<B99_9></B99_9><LastDay>TEST</LastDay>
这种做了我需要做的事情,但是对于我不知道标签之间的价值是什么的情况,我能做些什么呢?有没有办法在Replace函数的搜索中实现一些正则表达式,这样我可以搜索开始/结束标记,而不管它们之间的值是什么?
我知道这可能适用于CLR函数,但我真的很好奇,看看我是否可以通过使用t-sql来完成这项工作。提前谢谢!
答案 0 :(得分:2)
虽然很容易部署执行此操作的CLR代码,但SQL Server中没有开箱即用的正则表达式支持。
但是你可以在这种情况下使用标准的字符串函数
DECLARE @T TABLE
(
X VARCHAR(MAX)
);
INSERT INTO @T
VALUES ('<B99_9>TEST</B99_9><LastDay>TEST</LastDay>'),
('Some prefix <B99_9>TEST</B99_9><LastDay>TEST</LastDay>')
UPDATE [@T]
SET X = CASE
WHEN 0 IN ( StartIndex, EndIndex )
OR EndIndex <= StartIndex THEN X
ELSE STUFF(X, AdjStartIndex, EndIndex - AdjStartIndex, '')
END
FROM @T [@T]
CROSS APPLY (VALUES ('<B99_9>','</B99_9>')) V(StartString, EndString)
CROSS APPLY (VALUES (PATINDEX('%' + StartString + '%', X),PATINDEX('%' + EndString + '%', X))) V2(StartIndex, EndIndex)
CROSS APPLY (VALUES (StartIndex + LEN(StartString))) V3(AdjStartIndex)
SELECT *
FROM @T
但是,由于字符串是XML,将其存储在XML列中将允许您使用内置的,语义感知的XML方法而不是字符串解析来更新它。
DECLARE @T TABLE(X XML);
INSERT INTO @T
VALUES ('<B99_9>TEST</B99_9><LastDay>TEST</LastDay>'),
('Some prefix <B99_9>TEST</B99_9><LastDay>TEST</LastDay>')
UPDATE @T
SET X.modify('
replace value of (/B99_9/text())[1]
with "" ')
SELECT *
FROM @T
答案 1 :(得分:1)
如果由于安全原因你不习惯或者不能使用CLR
,那么在标准t-sql中使用CTE
有一种简单的方法。
这是一个完整的示例包含演示结构。你可以在整张桌子上运行它。
CREATE TABLE #dummyData(id int identity(1,1), teststring nvarchar(255))
INSERT INTO #dummyData(teststring)
VALUES(N'<B99_9>TEST</B99_9><LastDay>TEST</LastDay>, <B99_9>TEST</B99_9>, <B99_9></B99_9>')
DECLARE @starttag nvarchar(10) = N'<B99_9>', @endtag nvarchar(10) = N'</B99_9>'
;WITH cte AS(
SELECT id, STUFF(
teststring,
PATINDEX(N'%'+@starttag+N'[a-z0-9]%',teststring)+LEN(@starttag),
(PATINDEX(N'%[a-z0-9]'+@endtag+N'%',teststring)+1)-(PATINDEX(N'%'+@starttag+N'[a-z0-9]%',teststring)+LEN(@starttag)),
N''
) as teststring, 1 as iteration
FROM #dummyData
-- iterate until everything is replaced
UNION ALL
SELECT id, STUFF(
teststring,
PATINDEX(N'%'+@starttag+N'[a-z0-9]%',teststring)+LEN(@starttag),
(PATINDEX(N'%[a-z0-9]'+@endtag+N'%',teststring)+1)-(PATINDEX(N'%'+@starttag+N'[a-z0-9]%',teststring)+LEN(@starttag)),
N''
) as teststring, iteration+1 as iteration
FROM cte
WHERE PATINDEX(N'%'+@starttag+N'[a-z0-9]%',teststring) > 0
)
SELECT c.id, c.teststring
FROM cte as c
-- Join to get only the latest iteration
INNER JOIN (
SELECT id, MAX(iteration) as maxIteration
FROM cte
GROUP BY id
) as onlyMax
ON c.id = onlyMax.id
AND c.iteration = onlyMax.maxIteration
-- Cleanup
DROP TABLE #dummyData
如果要在更新中使用CTE
的结果。您只需使用以下代码替换CTE
- 定义后的部分:
UPDATE dd
SET teststring = c.teststring
FROM #dummyData as dd -- rejoin the base table for later update usage
INNER JOIN cte as c
ON dd.id = c.id
-- Join to get only the latest iteration
INNER JOIN (
SELECT id, MAX(iteration) as maxIteration
FROM cte
GROUP BY id
) as onlyMax
ON c.id = onlyMax.id
AND c.iteration = onlyMax.maxIteration
如果您不想在完整的表集上运行它,可以为单个变量运行以下代码:
DECLARE @string nvarchar(max) = N'<B99_9>TEST</B99_9><LastDay>TEST</LastDay>, <B99_9>TEST</B99_9>, <B99_9></B99_9>'
DECLARE @starttag nvarchar(10) = N'<B99_9>', @endtag nvarchar(10) = N'</B99_9>'
WHILE PATINDEX(N'%'+@starttag+N'[a-z0-9]%',@string) > 0 BEGIN
SELECT @string = STUFF(
@string,
PATINDEX(N'%'+@starttag+N'[a-z0-9]%',@string)+LEN(@starttag),
(PATINDEX(N'%[a-z0-9]'+@endtag+N'%',@string)+1)-(PATINDEX(N'%'+@starttag+N'[a-z0-9]%',@string)+LEN(@starttag)),
N''
)
END
SELECT @string