【问题标题】:how to replace second position string with new in sql server如何在sql server中用新的替换第二个位置字符串
【发布时间】:2018-08-24 09:04:49
【问题描述】:

我有一个问题:在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 中完成这项任务。

【问题讨论】:

  • happy 的两次出现是否总是相邻的,或者可能有一个字符串,例如happy New York happy new year,您也希望更改它?这将很难单独使用 SQL Server,因为它对正则表达式的支持很弱,这可能是这项工作的最佳工具。
  • 仅基于您的示例,这应该有效:SELECT replace ( name ,'happy happy' ,'happy new') afterreplacename FROM [test].[dbo].[stringrep](编辑:实际上几乎 - 一行中有一个双空格 - 所以它不会被替换)
  • 创建字符串拆分函数,它返回两列 rownumber 和 string column。执行此操作然后我们继续下一步。rownumber 因为您想用新的替换偶数。

标签: sql-server sql-server-2008 sql-server-2012


【解决方案1】:

我设法提出了以下查询。替换逻辑仅针对happy 至少出现两次的数据。如果是,那么我们找到happy第二次出现的索引,然后在new中找到STUFF作为替换。

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;

Demo

请注意,此解决方案对于在字符串中的任意位置出现两次(或多次)happy 是稳健的。请参阅此边缘情况的示例数据的最后一行。

我们宁愿在这里使用正则表达式,也许你的问题可以用一条线来回答。但是,SQL Server 没有很好的原生正则表达式支持,迫使我们改用基本字符串函数。

【讨论】:

  • 如果您将第二个“快乐”更改为“不快乐”,则输出包含 ID=7 的“新”。
  • @MJH 我不会更新,因为要处理你的边缘情况,以及你在蠕虫罐中拥有的任何其他东西,真的需要一个正则表达式引擎,这里没有。
  • 老实说不要怪你。我认为可以在字符串的前面添加一个空格(作为一个简单的解决方案),但随后您会遇到标点符号和各种不同的情况(如您所说,真正的蠕虫罐头)。
  • 您基本上需要添加逻辑来检测单词边界,这是编写原始正则表达式引擎的一半。回答是使用一些 UDF 会更好。
【解决方案2】:

我找到第二个出现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

【讨论】:

    【解决方案3】:

    如果... 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
    

    【讨论】:

      【解决方案4】:

      试试这个:

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-21
        • 2021-04-09
        • 2017-01-02
        相关资源
        最近更新 更多