Немного кода, я постараюсь объяснить
Сначала я использовал функцию split, собираюсь разделить varchar по данному varchar
CREATE FUNCTION [dbo].[fnSplitString](@str NVARCHAR(MAX),@sep NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH a AS(
SELECT CAST(0 AS BIGINT) AS idx1,
CHARINDEX(@sep,@str) idx2,
1 as [Level]
UNION ALL
SELECT idx2 + coalesce(nullif(LEN(@sep),0),1),
CHARINDEX(@sep,@str, idx2 + 1),
[Level] + 1 as [Level]
FROM a
WHERE idx2 > 0
)
SELECT SUBSTRING(@str,idx1,COALESCE(NULLIF(idx2,0),LEN(@str)+1)-idx1) AS Value,
[Level],
case when idx1 = 0 then 'R' when idx2 != 0 then 'LR' else 'L' end as Side
FROM a
Учитывая varchar 'красное воздушное шариковое небо' , и когда разделение является пробелом, оно выведет:
select *
from dbo.fnSplitString('red balloon sky', ' ')
Value Level Side
red 1 R
balloon 2 LR
sky 3 L
Сторона означает: если R, то пробел находится с правой стороны слова, если L, то пробел с левой стороны слова, а если LR, то слово окружено пробелами.
Когда разделение является «воздушный шар»
select *
from dbo.fnSplitString('red balloon sky', 'balloon')
red 1 R
sky 2 L
Таким образом, шар появляется с правой стороны красный и появляется с левой стороны небо
Имея эту полезную функцию, я создал еще одну функцию, которая выведет необходимый формат для одного предложения (varchar)
create FUNCTION [dbo].[fnGetPartsFromSentence](@sentence NVARCHAR(MAX),@word NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
with RawData as
(select rtrim(ltrim(f.Value)) as LR,
(select COUNT (*) from dbo.fnSplitString(rtrim(ltrim(f.Value)), ' ')) as NumberOfWords,
f.Side,
0 as SideLevel
from dbo.fnSplitString(@sentence, @word) as f
where f.Side = 'R' or f.Side = 'L'
union all
(
select rtrim(ltrim(f.Value)) as LR,
(select COUNT (*) from dbo.fnSplitString(rtrim(ltrim(f.Value)), ' ')) as NumberOfWords,
f.Side,
sl.no as SideLevel
from dbo.fnSplitString(@sentence, @word) as f
join (select 1 as no union all select 2) sl on 1 = 1
where f.Side = 'LR'
)
)
select (case when Side = 'R' then LR + ' ' + @word
when Side = 'L' then @word + ' ' + LR
when Side = 'LR' then
(
case when SideLevel = 1 then @word + ' ' + LR
when SideLevel = 2 then LR + ' ' + @word
end
)
end) as SentencePart,
(case when Side = 'R' or Side = 'L' then Side
else
( case when SideLevel = 1 then 'L'
when SideLevel = 2 then 'R'
end
)
end) as Side,
NumberOfWords
from RawData
Эта функция использует предыдущую. Сначала он разбивает предложение по словам и считает слова в разделениях, выполняя еще одно разделение по пробелам. Когда слово появляется с обеих сторон разделения, оно повторяет разделение (которое объединяется с 1, 2 значениями).
Эта функция также будет выводить разделение, соединенное со словом, в зависимости от того, с какой стороны оно находится: слева, справа или оба. Он также выведет сторону, на этот раз влево или вправо.
select *
from [dbo].[fnGetPartsFromSentence]('yellow balloon sky road','balloon')
SentencePart Side NumberOfWords
yellow balloon R 1
balloon sky road L 2
Теперь, используя эту функцию, я могу скрестить ее с таблицей
declare @table table(Sentence varchar(250))
insert into @table(sentence)
values ('red balloon sky'),
('yellow balloon sky road'),
('blue balloon chair')
select SentencePart, NumberOfWords
from @table
cross apply dbo.fnGetPartsFromSentence(Sentence, 'balloon') f
order by
case when f.Side = 'R' then 0
else 1 end
Выход
red balloon 1
yellow balloon 1
blue balloon 1
balloon chair 1
balloon sky road 2
balloon sky 1
Работает и при наличии нескольких случаев