Допустим, у меня есть таблица T со столбцом S.
Я хочу удалить каждую подстроку в каждой строке TS, которая находится между \ и \, и заменить ее ничем, чтобы таблица T стала
Я понял, как идентифицировать символы между первым экземпляром \ и \
IF OBJECT_ID(N'tempdb..#t') IS NOT NULL
BEGIN -- Checking to ensure temp table does not exist, and dropping anyone that does to avoid errors
DROP TABLE #t;
END;
GO
--- Create Temp Table to store values and manipulate before inserting into production table ----
CREATE TABLE #t
(
Code VARCHAR(MAX)
,S VARCHAR(MAX)
);
INSERT INTO #t (Code ,S )
VALUES ('1','\String\ String'),
('2','Laser \Laser\'),
('3', 'La\ser\s and \S\trings')
SELECT *
FROM #t;
SELECT REPLACE(REPLACE(SUBSTRING(s, start_pos, end_pos - start_pos
+1), '\', '\'), '\', '\')
FROM (SELECT s,
CHARINDEX('\', s) AS start_pos,
CHARINDEX('\', s, CHARINDEX('\', s) + 1) AS end_pos
FROM #t) t
Это возвращает
Я застрял на
Как мне заставить его применяться ко всем экземплярам \\ в одной и той же строке индивидуально (см. строку 3)
Примените это изменение к столбцу в обновлении (я думаю, здесь может быть полезно перекрестное применение)


Если бы это был SQL Server 2022 (или более поздняя версия), мы могли бы:
STRING_SPLIT(,,1), чтобы разбить строку на разделители \ и присвоить каждой части значение ordinal.STRING_AGG().TRIM(), чтобы очистить начальные или конечные пробелы.Что-то вроде:
SELECT
T.Code,
TRIM(STRING_AGG(SS.value, '') WITHIN GROUP(ORDER BY SS.ordinal)) AS Answer
FROM #t T
CROSS APPLY STRING_SPLIT(T.S, '\', 1) SS
WHERE SS.ordinal % 2 != 0 -- Keep the odd parts
GROUP BY T.Code
Третий параметр STRING_SPLIT() генерирует ordinal вдоль каждой value (доступно в SQL Server 2022 и более поздних версиях). На это есть ссылка в предложении WITHIN GROUP(...) функции STRING_AGG(), чтобы гарантировать правильный порядок или повторную сборку компонентов.
Если это часть более сложного запроса, вы можете инкапсулировать логику в CROSS APPLY, на результат которого затем можно будет ссылаться в другом месте.
SELECT
T.Code,
CA.Answer
FROM #t T
CROSS APPLY (
SELECT TRIM(STRING_AGG(SS.value, '') WITHIN GROUP(ORDER BY SS.ordinal)) AS Answer
FROM STRING_SPLIT(T.S, '\', 1) SS
WHERE SS.ordinal % 2 != 0 -- Keep the odd parts
) CA
ORDER BY T.Code
В SQL Server 2019 функция STRING_SPLIT() не поддерживает опцию enable_ordinal, поэтому эту функцию нельзя использовать, когда нам нужно гарантировать порядок. Альтернативой является использование метода, который сначала отображает строку в массив JSON, а затем использует OPENJSON() для анализа этого массива.
SELECT
T.Code,
CA.Answer
FROM #t T
CROSS APPLY (
SELECT TRIM(STRING_AGG(SS.value, '') WITHIN GROUP(ORDER BY SS.ordinal)) AS Answer
FROM (
SELECT J.value, CONVERT(int, [key]) + 1 AS ordinal
FROM OPENJSON(CONCAT('["', REPLACE(STRING_ESCAPE(T.S, 'json'), '\\', '","'), '"]')) J
) SS
WHERE SS.ordinal % 2 != 0 -- Keep the odd parts
) CA
ORDER BY T.Code
Приведенное выше преобразует исходную строку в массив JSON, который затем анализируется на отдельные элементы с помощью OPENJSON(). Функция STRING_ESCAPE() защищает JSON от определенных специальных символов (особенно от любых встроенных двойных кавычек), которые в противном случае могли бы вызвать ошибку. Значение key, возвращаемое OPENJSON() выше, представляет собой строку с отсчетом от нуля, которую необходимо преобразовать в целое число и сместить на 1, чтобы она соответствовала STRING_SPLIT()ordinal.
ПРИМЕЧАНИЕ. Существует несколько STRING_SPLIT() альтернатив, но немногие из них дают надежную ordinal ценность. (На самом деле существует несколько плохих ответов, в которых используется логика нумерации после разделения, которая, кажется, работает, но результаты которой не гарантируются какой-либо документированной функцией и которая может сломаться в любой момент - особенно при масштабировании.)
Результаты одинаковы для каждого из вышеперечисленных:
См. эту db<>fiddle для демонстрации.
Обновление на месте можно выполнить следующим образом:
UPDATE T
SET S = CA.Answer
FROM #t T
CROSS APPLY (
SELECT TRIM(STRING_AGG(SS.value, '') WITHIN GROUP(ORDER BY SS.ordinal)) AS Answer
FROM (
SELECT J.value, CONVERT(int, [key]) + 1 AS ordinal
FROM OPENJSON(CONCAT('["', REPLACE(STRING_ESCAPE(T.S, 'json'), '\\', '","'), '"]')) J
) SS
WHERE SS.ordinal % 2 != 0 -- Keep the odd parts
) CA
Или, если вы предпочитаете включить расчет непосредственно в оператор выбора:
UPDATE T
SET S = (
SELECT TRIM(STRING_AGG(SS.value, '') WITHIN GROUP(ORDER BY SS.ordinal))
FROM (
SELECT J.value, CONVERT(int, [key]) + 1 AS ordinal
FROM OPENJSON(CONCAT('["', REPLACE(STRING_ESCAPE(T.S, 'json'), '\\', '","'), '"]')) J
) SS
WHERE SS.ordinal % 2 != 0 -- Keep the odd parts
)
FROM #t T
Посмотрите эту обновленную базу данных<>скрипку.
@ThomasShort - Увидев тег версии SQL Server в исходном вопросе, я обновил приведенный выше ответ, включив в него версию кода 2019 года. См. раздел выше, начинающийся с «для SQL Server 2019...».
Хорошо, спасибо. Я пытаюсь обновить таблицу сейчас ''' UPDATE ST SET S = (SELECT ST2.Code,CA.Answer FROM #t ST2 CROSS APPLY ( SELECT TRIM(STRING_AGG(SS.value, '') Within GROUP(ORDER BY SS. порядковый номер)) AS Ответ FROM ( SELECT J.value, CONVERT(int, [key]) + 1 AS порядковый номер FROM OPENJSON(CONCAT('["', REPLACE(STRING_ESCAPE(ST2.S, 'json'), '\\ ', '","'), '"]')) J ) SS WHERE SS.ordinal % 2 != 0 -- Сохраняем нечетные части ) CA ) FROM dbo.#t ST''' Выдает только ошибку в списке выбора можно указать одно выражение, если подзапрос не введен с помощью EXISTS.
По сути, как мне структурировать это в операторе обновления, чтобы я мог использовать обновленную таблицу в конце моего запроса. Я пробовал использовать внутренние соединения, использовать существует, и я не могу правильно понять синтаксис.
Ответ проще. Поскольку оператор SELECT, опубликованный ранее, уже обращается к таблице и вычисляет ответ, достаточно просто заменить предложение SELECT ... на UPDATE T SET S = CA.Answer. Смотрите мой обновленный ответ выше.
См. пример с рекурсивным запросом
with r as (
select 0 lvl, code,s
,case when CHARINDEX('\', s)>0 and CHARINDEX('\', s, CHARINDEX('\', s) + 1)>0 then
substring(s,1,CHARINDEX('\', s)-1)
+substring(s,CHARINDEX('\', s, CHARINDEX('\', s) + 1)+1,len(s))
else s
end rest
from #t
union all
select r.lvl+1,code,s
,case when CHARINDEX('\', rest)>0
and CHARINDEX('\',rest, CHARINDEX('\',rest) + 1)>0 then
substring(rest,1,CHARINDEX('\', rest)-1)
+substring(rest,CHARINDEX('\', rest, CHARINDEX('\', rest) + 1)+1,len(s))
else rest
end rest
from r where CHARINDEX('\', rest)>0 and CHARINDEX('\',rest, CHARINDEX('\',rest) + 1)>0
)
update #t
set s=rest
from #t t
left join(
select * ,max(lvl)over(partition by code) rn
from r
)src on src.code= t.code and src.rn=src.lvl
для тестовых данных
Я получаю сообщение об ошибке «String_Split — недопустимое имя объекта».