Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
Есть вот такой столбец:
abcdefghijklmnopqrstuvwxyz
abcd#tt2 efghijklmnopqrstuvwxyz
abcd#t5 efghijklmnopqrstuvwxyz
abcd#ttt9 efghijklmnopqrstuvwxyz
abcd#tt173 efghijklmnopqrstuvwxyz
Я понимаю, что строки, содержащие комбинацию '#t...Пробел', одинаковы и мне нужно их сгруппировать, но из-за разного текста в этой комбинации не группируются. Поэтому появилась необходимость в замене одинаковым текстом.
Пробовал:
where TextData like '#%[t0123456789]% '
Не работает, ничего не выдает.
Как это сделать?
7 июл 17, 18:49    [20624506]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
Col
Member

Откуда: Торонто
Сообщений: 177
okwell5,
Вот с этого надо было начинать:
USE TEMPDB 
GO
DROP TABLE [dbo].[tbl01]
GO
CREATE TABLE [dbo].[tbl01](
      [ID] INT IDENTITY(1,1) ,
      [String] VARCHAR (100) NOT NULL)
GO
INSERT INTO dbo.[tbl01] ([String]) 
VALUES ('abcdefghijklmnopqrstuvwxyz')
GO
INSERT INTO dbo.[tbl01] ([String]) 
VALUES ('abcd#tt2 efghijklmnopqrstuvwxyz')
GO
INSERT INTO dbo.[tbl01] ([String]) 
VALUES ('abcd#t5 efghijklmnopqrstuvwxyz')
GO
INSERT INTO dbo.[tbl01] ([String]) 
VALUES ('abcd#ttt9 efghijklmnopqrstuvwxyz')
GO
 INSERT INTO dbo.[tbl01] ([String]) 
VALUES ('abcd#tt173 efghijklmnopqrstuvwxyz')
GO
--Browse the data
SELECT * FROM dbo.[tbl01]
GO


Примерно вот так:

USE TEMPDB 
GO
 
DECLARE @delimiter VARCHAR(50)
SET @delimiter=' '  -- <=== Here, you can change the delimiter.
;WITH CTE AS
( 
    SELECT
        [ID], 
        [String],
        CAST('<M>' + REPLACE([String], @delimiter , '</M><M>') + '</M>' AS XML)
        AS [String XML]
    FROM  [tbl01] 
)
/*SELECT
     [ID], 
     [String],
     [String XML].value('/M[1]', 'varchar(50)') As [Left],
     [String XML].value('/M[2]', 'varchar(50)') As [Right]
	 from CTE
	 */
SELECT
     [ID], 
     [String],
     [String XML].value('/M[1]', 'varchar(50)') + '   mytext here    '+
     [String XML].value('/M[2]', 'varchar(50)') As [Result]
  
FROM CTE 
GO
7 июл 17, 21:26    [20624756]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
invm
Member

Откуда: Москва
Сообщений: 9122
declare @t table (s varchar(100));

insert into @t
values
 ('abcdefghijklmnopqrstuvwxyz'),
 ('abcd#tt2 efghijklmnopqrstuvwxyz'),
 ('abcd#t5 efghijklmnopqrstuvwxyz'),
 ('abcd#ttt9 efghijklmnopqrstuvwxyz'),
 ('abcd#tt173 efghijklmnopqrstuvwxyz');

select
 c.s, count(*)
from
 @t t cross apply
 (select nullif(charindex('#t', t.s), 0)) a(p) cross apply
 (select nullif(charindex(' ', t.s, a.p), 0)) b(p) cross apply
 (select isnull(stuff(t.s, a.p, b.p - a.p + 1, ''), t.s)) c(s)
group by
 c.s;
7 июл 17, 22:09    [20624845]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
Col, Пробел я еще увидел, но вот кусочка '#t' нигде нет. Т.е. изначально как-то громоздко и неверно. Я привел пример с регулярным выражением, полагая, что эту задачу можно решить именно регулярным выражением; просто я не знаю, как его составить.
7 июл 17, 22:45    [20624917]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
invm, Магия кода! Спасибо, сработало! Только вот неизвестно, насколько такое решение возможно применить в жизни: у меня тут таблица на пару млн строк с разными полями (Duration bigint, SPU int, Reads bigint, BinaryData image).
Неужели никак не решить регулярным выражением?
7 июл 17, 23:22    [20624993]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 30768
okwell5
Неужели никак не решить регулярным выражением?

Нету в сиквеле регулярных выражений.

Найти искомые строки можно условием:
where TextData like '%#t% %' 

но заменить эти символы на другие таким способом невозможно.
okwell5
Только вот неизвестно, насколько такое решение возможно применить в жизни: у меня тут таблица на пару млн строк с разными полями (Duration bigint, SPU int, Reads bigint, BinaryData image).
Скорость у варианта invm будет такая же плохая, как и в варианте с like, потому что это по любому сканирование таблицы.

Ускорить можно только нормализацией.
7 июл 17, 23:37    [20625050]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
invm
Member

Откуда: Москва
Сообщений: 9122
okwell5
Только вот неизвестно, насколько такое решение возможно применить в жизни: у меня тут таблица на пару млн строк с разными полями
Предлагаете провести тестирование предложенного способа на таблице в пару миллионов строк? Может быть сами попробуете?
К сведению:
- пара миллионов строк - это мизер
- группировка съест гораздо больше ресурсов, чем манипуляции со строками.
okwell5
Неужели никак не решить регулярным выражением?
Можно решить. Только где вы видели в MSSQL регулярные выражения?
Конечно можете найти готовую CLR-библиотеку для манипуляций регулярными выражениями. Их полно.
Тут на форуме даже есть - https://www.sql.ru/forum/1144247-a/faq-regex-parsim-zamenyaem-razbivaem-krutim-vertim
7 июл 17, 23:49    [20625091]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
okwell5, косячок все же и в формулировке задачи, и впоследствии в решении.
комбинаций '#t... ' ведь может быть несколько в одной строке, а заменяется только первая.
7 июл 17, 23:59    [20625143]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
invm, уже попробовал :) Процессор загрузил на 100%, минут семь формировалось.
SQL-серверу выделено 20000 Мб
2-процессорный, 16-ядер всего
Это при отсутствии прочей нагрузки.
8 июл 17, 00:06    [20625169]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7399
okwell5,

Вы же заменить хотите, а мутите что-то странное. Возьмите первое выражение до пробела, возьмите второе выражение от второго пробела до конца, между ними вставляйте замену. Конкатенируйте.
9 июл 17, 22:19    [20627619]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
Владислав Колосов, легко так просто сказать, да непросто сделать, поэтому и задал вопрос на форме.
Вот, как, например, заменить, как Вы говорите, в таком столбце?
"abcd#tt2 efghijklmnopqrstuvwxyz"
"abcd#tt2 efghijk #tt1 lmnopq#tt9 rstu #tt5 vwxyz xyz"
"abcd#tt1104 efghijk #tt254 lmnopq#tt90 rstu #tt8 vwxyz xyz"
Мне вот в голову не приходит, а именно подобные ситуации у меня в реальной таблице.
10 июл 17, 08:30    [20627875]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
Massa52
Member

Откуда:
Сообщений: 373
okwell5
okwell5, косячок все же и в формулировке задачи, и впоследствии в решении.
комбинаций '#t... ' ведь может быть несколько в одной строке, а заменяется только первая.

Прогонять скрипт
invm
до тех пор пока все не заменятся :)
10 июл 17, 08:36    [20627878]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
iap
Member

Откуда: Москва
Сообщений: 46953
Нужно сделать замену одного слова на другое
10 июл 17, 10:06    [20628070]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
Col
Member

Откуда: Торонто
Сообщений: 177
okwell5
Пробел я еще увидел, но вот кусочка '#t' нигде нет. Т.е. изначально как-то громоздко и неверно.

Я вообще-то откоментил где делиметр меняется.
Там же одним проходом без единого джоина, это громоздко?
47 секунд на 1,25 миллионах записей.

П.С.
Код в процедуру, быстрее разве что пакетом распарсить, сразу по куче условий ;)
12 июл 17, 15:01    [20637287]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
SFlash
Member

Откуда:
Сообщений: 143
Col,

update [tbl01]
set String=REPLACE(String,SUBSTRING(String,CHARINDEX('#t',string), CHARINDEX(' ',string,CHARINDEX('#t',string)+1)-CHARINDEX('#t',string)+1),'_Replaced_') from [tbl01]


Меняет только первое вхождение
Для двух надо еще раз проапдейтить, или вложить двойной REPLACE, для трех соответственно три раза и т.д.
13 июл 17, 13:20    [20640479]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
SFlash, результаты не сходятся. Только для первого прохода норм.
select * from test3 

declare @tt nvarchar(3) = '#tt'
declare @maxtt int = 1
set @maxtt = (SELECT max((dataLENGTH(TextData) - dataLENGTH(REPLACE(TextData, @tt, ''))) / dataLENGTH(@tt)) from test2)
 
declare @dinamicSQL nvarchar(max) = 'TextData'
declare @i int = 1
while @i <= @maxtt
begin
	set @dinamicSQL = 'REPLACE('+@dinamicSQL
						+',SUBSTRING('+@dinamicSQL+', CHARINDEX(''#t'','+@dinamicSQL+'), CHARINDEX('' '','+@dinamicSQL+',CHARINDEX(''#t'','+@dinamicSQL+')+1)-CHARINDEX(''#t'',TextData)+1)'
						+','' TempTable '')'
	set @i = @i + 1
end
set @dinamicSQL = 'update test3 set TextData=' + @dinamicSQL + ' from test3'
select @dinamicSQL
execute(@dinamicSQL)
select * from test3


Before
1 abcdefghijklmnopqrst uvwxyz
2 àáâãäåžæçèéêëìíîïðñòóôõö÷øùüûúýþÿ
3 abcdefghijklmnopqrstuvwxyz
4 abcd#tt2 efghijklmnopqrstuvwxyz
5 abcd#tt5 efghijklmnopqrstuvwxyz
6 abcd#tt2 efghijk #tt1 lmnopq#tt9 rstu #tt5 vwxyz xyz
7 abcd#tt1104 efghijk #tt254 lmnopq#tt90 rstu #tt8 vwxyz xyz

After
1 TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable TempTable uvwxyz
2 àáâãäåžæçèéêëìíîïðñòóôõö÷øùüûúýþÿ
3 abcdefghijklmnopqrstuvwxyz
4 abcd TempTable efghijklmnopqrstuvwxyz
5 abcd TempTable efghijklmnopqrstuvwxyz
6 abcd TempTable efghijk TempTable 5 vwxyz xyz
7 abcd TempTable efghijk TempTable t8 vwxyz xyz

К сообщению приложен файл (DinamicString.txt - 22Kb) cкачать
25 июл 17, 10:05    [20672044]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
iap, решает не эту задачу, там просто заменяется слово, как в replace. Пробовал на своем примере - не отрабатывает, пытался менять делиметр, но бесполезно.
27 июл 17, 00:16    [20678299]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
invm, подключил как раз эту CLR-библиотеку. Только какое теперь регулярное выражение должно быть?
Пробую ext.Regex_Replace(TextData, '#tt[0-9] ', 'TempTable ', ''), но почему-то меняет только, если после #tt одна цифра, т.е. #tt5 заменит, а #tt55 не меняет и т.д.
27 июл 17, 01:14    [20678341]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
invm
Member

Откуда: Москва
Сообщений: 9122
okwell5
Только какое теперь регулярное выражение должно быть?
'#t.* '
27 июл 17, 10:24    [20678822]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
invm, Код:
select id, ext.Regex_Replace(TextData, '#t.* ', 'TempTable ', '') as res from test3

Результат:
1 abcdefghijklmnopqrst uvwxyz
2 абвгдеёжзийклмнопрстуфхцчшщьыъэюя
3 abcdefghijklmnopqrstuvwxyz
4 abcdTempTable efghijklmnopqrstuvwxyz
5 abcdTempTable efghijklmnopqrstuvwxyz
6 abcdTempTable xyz
7 abcdTempTable xyz
Снова мимо.
27 июл 17, 23:22    [20681164]     Ответить | Цитировать Сообщить модератору
 Re: Как заменить текст между двумя разными символами?  [new]
okwell5
Member

Откуда:
Сообщений: 116
Вот решение, конечно, не универсальное, но для четырехзначных чисел подойдет. Если будет больше, то, соответственно, обволакиваем дополнительными реплэйсами.
update test3 set TextData = 
  ext.Regex_Replace(
						ext.Regex_Replace(
											ext.Regex_Replace(
																ext.Regex_Replace(TextData, '#tt[0-9][0-9][0-9][0-9] ', 'TempTable ', '')
																,'#tt[0-9][0-9][0-9] '
																,'TempTable ', ''
															)
											,'#tt[0-9][0-9] '
											,'TempTable ', ''
										)
						,'#tt[0-9] '
						,'TempTable ', ''
					)


Результат:
1 abcdefghijklmnopqrst uvwxyz
2 абвгдеёжзийклмнопрстуфхцчшщьыъэюя
3 abcdefghijklmnopqrstuvwxyz
4 abcdTempTable efghijklmnopqrstuvwxyz
5 abcdTempTable efghijklmnopqrstuvwxyz
6 abcdTempTable efghijk TempTable lmnopqTempTable rstu TempTable vwxyz xyz
7 abcdTempTable efghijk TempTable lmnopqTempTable rstu TempTable vwxyz xyz
Цель достигнута, задача решена, хотя не универсально.
28 июл 17, 00:22    [20681235]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить