как заменить вторую строку позиции на новый в SQL Server - PullRequest
0 голосов
/ 24 августа 2018

У меня один вопрос: на сервере sql, как заменить 2-е вхождение строки 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.

Ответы [ 4 ]

0 голосов
/ 24 августа 2018

Попробуйте это:

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
0 голосов
/ 24 августа 2018

Я нахожу второе вхождение 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
0 голосов
/ 24 августа 2018

Это было бы просто RegEx, если ... SQL Server поддерживает RegExes. Я рекомендую использовать другой инструмент для замены значений - любой основной язык программирования с доступом к базе данных и поддержкой 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
0 голосов
/ 24 августа 2018

Мне удалось сформулировать следующий запрос.Логика замены предназначена только для данных, у которых 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;

enter image description here

Демонстрация

Обратите внимание, что это решение устойчиво к двум (или более) вхождениям happy в любом месте строки.См. Последнюю строку примера данных для этого граничного случая.

Мы бы предпочли использовать здесь регулярное выражение, и, возможно, на ваш вопрос можно ответить с помощью одной строки.Но SQL Server не имеет хорошей поддержки собственных регулярных выражений, что вынуждает нас вместо этого использовать функции базовой строки.

...