我有一个问题:在sql server中,如何将字符串happy
的第二次出现替换为字符串new
,否则保持原样(相同)。
表格:
CREATE TABLE [dbo].[stringrep](
[name] [varchar](100) NULL,
[id] [int] NULL
)
INSERT [dbo].[stringrep] ([name], [id]) VALUES (N'happy happy year', 1)
GO
INSERT [dbo].[stringrep] ([name], [id]) VALUES (N'very happy new year', 2)
GO
INSERT [dbo].[stringrep] ([name], [id]) VALUES (N'happy new year hello', 3)
GO
INSERT [dbo].[stringrep] ([name], [id]) VALUES (N'happy happy year', 4)
GO
INSERT [dbo].[stringrep] ([name], [id]) VALUES (N'heloo year happy', 5)
GO
INSERT [dbo].[stringrep] ([name], [id]) VALUES (N'happy happy happy year', 6)
GO
基于上述数据,我希望输出如下:
id | Name
1 | happy new year
2 | very happy new year
3 | happy new year hello
4 | happy new year
5 | heloo year happy
6 |happy new happy year
我尝试了以下查询:
SELECT replace ( name ,'happy happy year' ,'happy new year')afterreplacename,
replace ( name, substring ('happy happy year' ,6,6) ,' new')anotherway
,name ,[id]
FROM [test].[dbo].[stringrep]
上面的查询没有给出预期的结果。
请告诉我如何在sql server中完成此任务。
答案 0 :(得分:2)
我设法提出以下查询。替换逻辑仅针对至少发生两次的happy
数据。如果是这样,那么我们找到第二次出现的happy
的索引,然后在STUFF
中找到new
作为替换。
SELECT
data,
CASE WHEN LEN(REPLACE(data, 'happy', '')) < LEN(data) - 6
THEN STUFF(data,
CHARINDEX('happy', data, CHARINDEX('happy', data) + 1),
5,
'new')
ELSE data END AS new_data
FROM yourTable;
请注意,此解决方案对于出现在字符串中任何位置的happy
的两次(或更多次)事件是可靠的。有关这种极端情况,请参阅示例数据的最后一行。
我们想在这里使用正则表达式,也许您的问题可以单线回答。但是,SQL Server没有良好的本机正则表达式支持,因此我们不得不使用基本字符串函数。
答案 1 :(得分:0)
我发现第二次出现的happy
,如果只有一次出现的happy
返回了原始字符串,否则该字符串被分割了。我得到单词happy
第二次出现之前的状态+ new
+单词happy
第二次出现之后的一切。
SELECT
CASE
WHEN CHARINDEX('happy', [name], (CHARINDEX('happy', [name])+1)) <> 0 THEN
SUBSTRING([name],0,CHARINDEX('happy', [name], (CHARINDEX('happy', [name])+1)))
+ 'new '
+ SUBSTRING([name],CHARINDEX('happy', [name], (CHARINDEX('happy',
[name])+1))+5,100)
ELSE [name]
END
FROM [dbo].[stringrep]
输出:
happy new year
very happy new year
happy new year hello
happy new year
heloo year happy
happy new happy year
答案 2 :(得分:0)
如果... SQL Server支持RegExes,那将是简单的RegEx。我建议使用其他工具替换值-具有数据库访问和RegEx支持的任何主要编程语言。如果这是经常操作,请使用CLR Functions。然后,请记住:
迭代是人的,递归神圣的
这就是为什么:
WITH Splitter AS
(
SELECT id, 1 num, SUBSTRING(name, 1, charindex(' ',name)-1) Word, SUBSTRING(name, charindex(' ',name), LEN(name)) Rest FROM stringrep
UNION ALL
SELECT
id,
num+1 num,
CASE WHEN charindex(' ',Rest)=1 THEN ' '
WHEN charindex(' ',Rest)=0 THEN Rest
ELSE SUBSTRING(Rest, 1, charindex(' ',Rest)-1) END Word,
CASE WHEN charindex(' ',Rest)=1 THEN SUBSTRING(Rest, 2, LEN(Rest))
WHEN charindex(' ',Rest)=0 THEN ''
ELSE SUBSTRING(Rest, charindex(' ',Rest), LEN(Rest)) END Rest
FROM Splitter
WHERE LEN(rest)>0
), Replacer AS
(
SELECT S1.id, S1.num, CASE WHEN LastNotSpace='happy' AND Word='happy' AND (LastLastNotSpace IS NULL OR LastLastNotSpace!='happy') THEN 'new' ELSE Word END NewWord
FROM Splitter S1
LEFT JOIN (SELECT id,num,LAG(Word) OVER (PARTITION BY id ORDER BY num) LastNotSpace, LAG(Word,2) OVER (PARTITION BY id ORDER BY num) LastLastNotSpace FROM Splitter WHERE Word!=' ') T ON S1.id=T.id AND S1.num=T.num
), Joiner AS
(
SELECT id, num, CAST(NewWord AS nvarchar(MAX)) Joined FROM Replacer WHERE num=1
UNION ALL
SELECT S.id, S.num, J.Joined+S.NewWord Joined FROM Joiner J
JOIN Replacer S ON J.id=S.id AND J.num+1=S.num
), Filter AS
(
SELECT id, Joined FROM (
SELECT id, num, Joined, ROW_NUMBER() OVER (PARTITION BY id ORDER BY num DESC) Lev FROM Joiner
) T WHERE Lev=1
)
SELECT * FROM Filter
答案 3 :(得分:0)
尝试一下:
select [name], id,
case when secondIndex > 0 then stuff([name], secondIndex, 5, 'new') else [name] end newName
from (
select [name], id, charindex('happy', [name], charindex('happy', [name]) + 1) secondIndex
from #stringrep
) a