CPuser2020 Ответов: 2

Разделите строку, а затем объедините слова в SQL


Здравствуйте, у меня есть 2 стола:

Account(ID(PK), Name, Country)
AccountSubstrings(accSubstringID(PK), AccountID, substring)


В таблице Account, столбце 'Name', мне нужно разделить строку на отдельные слова, а затем объединить разделенные слова, начиная с другого первого слова каждый раз. Эти новые подстроки будут вставлены в новую строку таблицы AccountSubstrings.

Я хочу сделать функцию или хранимую процедуру, чтобы сделать это, как я буду проходить в @Name из таблицы счетов.

Например, одно "имя" в таблице счетов:
@Name = 'This is a sentence'

Это должно быть отделено как таковое:

This
Thisis
Thisisa
Thisisasentence
is
isa
isasentence
a
asentence
sentence



Если кто-нибудь знает, как я мог бы достичь этого в качестве функции для передачи в моей колонке, пожалуйста, дайте мне знать!Спасибо!

Что я уже пробовал:

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

declare @s varchar(max) = 'This is a sentence';

with words as (
      select s.value as word, row_number() over (order by charindex(s.value, @s)) as seqnum
      from string_split(@s, ' ') s
     ),
     cte as (
      select seqnum, word as combined, format(seqnum, '000') as seqnums
      from words
      union all
      select w.seqnum, concat(cte.combined, ' ', w.word), concat(seqnums, ':', format(w.seqnum, '000'))
      from cte join
           words w
           on w.seqnum = cte.seqnum + 1
     )
select *
from cte
order by seqnums;

Richard MacCutchan

Разделите строку на массив.

For each word in array
    For each nextword in array + 1
        Append nextword to word

2 Ответов

Рейтинг:
2

Maciej Los

Проверить это:

DECLARE @s VARCHAR(150) = 'This is a sentence';

DECLARE @tmp TABLE (WordID INT IDENTITY(1,1), Sentence VARCHAR(150), Word VARCHAR(30), DelimPos INT)

INSERT INTO @tmp (Sentence, Word, DelimPos)
SELECT @s, s.value, CHARINDEX(s.value, @s)
FROM STRING_SPLIT(@s, ' ') s;


WITH CTE AS
(
	--initial query
	SELECT 1 AS LoopNo, WordID, Sentence, Word, DelimPos, CONVERT(VARCHAR(MAX), Word) As NewSentence
	FROM @tmp
	--recursive part
	UNION ALL
	SELECT LoopNo + 1 AS LoopNo, t2.WordID, t2.Sentence, t2.Word, t2.DelimPos, CONCAT(NewSentence, t2.Word) AS NewSentence
	FROM CTE t1 INNER JOIN @tmp t2 ON t1.WordID  +1 =  t2.WordID 
	WHERE t1.WordID<= LoopNo +2
)
SELECT LoopNo, RowNo, NewSentence
FROM
(
	SELECT LoopNo, WordID, Word, DelimPos, NewSentence, DENSE_RANK() OVER(PARTITION BY LoopNo ORDER BY WordID) RowNo
	FROM CTE 
) T
ORDER BY RowNo, DelimPos


Результат:
LoopNo	RowNo	NewSentence
1		1		This
2		1		Thisis
3		1		Thisisa
4		1		Thisisasentence
1		2		is
2		2		isa
3		2		isasentence
1		3		a
2		3		asentence
1		4		sentence


;)


CPuser2020

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

Maciej Los

Следовать инструкциям: Создание пользовательских функций (компонент Database Engine) - SQL Server | Microsoft Docs[^]
Я считаю, что мой ответ решает вашу проблему, даже если вы не можете использовать его внутри функции...
Итак, можете ли вы принять его, чтобы удалить свой вопрос из списка без ответа?

CPuser2020

Привет Павел, спасибо большое. Хотя это работает для "это предложение", оно все еще не отвечает на мой вопрос так, как нужно. Мне нужно, чтобы он принимал различные строки из столбца " имя "в таблице " учетная запись". "Это предложение" было приведено в качестве примера того, как мне нужно, чтобы строки выглядели. Решение, которое я добавил в свой вопрос, также дало желаемый результат, но не принимает в колонке, и именно поэтому я разместил его здесь. Спасибо за статью, я уже читал это раньше

Maciej Los

См. решение № 2.

Maciej Los

И...

CPuser2020

Привет, Мацей, у меня есть шанс попробовать это только сейчас. Это работает, большое спасибо за вашу помощь, очень ценю

Рейтинг:
12

Maciej Los

В соответствии с комментариями к решению№1...

Вы должны создать функцию: Создание пользовательских функций (компонент Database Engine) - SQL Server | Microsoft Docs[^]

USE [test] --my test database, you need to use your database name
GO

IF OBJECT_ID (N'dbo.udf_SentenceToMulti', N'TF') IS NOT NULL  
    DROP FUNCTION dbo.udf_SentenceToMulti;  
GO  


--@AccountId refers to ID field in Account table
--@Name refers to Name field in Account table
CREATE FUNCTION [dbo].[udf_SentenceToMulti](@AccountId INT, @Name VARCHAR(150))
RETURNS @tmpTable TABLE 
(
	SubSentenceId INT PRIMARY KEY NOT NULL, 
	AccountId INT NOT NULL,
	NewSentence VARCHAR(MAX) NOT NULL
)
AS
BEGIN
	WITH InitialTable AS
	(
		SELECT @AccountId AS AccountId,  s.value AS Word, ROW_NUMBER() OVER(ORDER BY CHARINDEX(s.value, @Name)) AS WordId
		FROM STRING_SPLIT(@Name, ' ') s
	), CTE AS
	(
		--initial query
		SELECT 1 AS LoopNo, AccountId, WordID, Word, CONVERT(VARCHAR(MAX), Word) As NewSentence
		FROM InitialTable
		--recursive part
		UNION ALL
		SELECT LoopNo + 1 AS LoopNo, t2.AccountId, t2.WordID, t2.Word, CONCAT(NewSentence, t2.Word) AS NewSentence
		FROM CTE t1 INNER JOIN InitialTable t2 ON t1.WordID  +1 =  t2.WordID 
		WHERE t1.WordID<= LoopNo +2
	)
	INSERT INTO @tmpTable 
	SELECT ROW_NUMBER() OVER(ORDER BY RowNo, LoopNo) AS SubSentenceId, AccountID, NewSentence
	FROM
	(
		SELECT WordID, AccountId, NewSentence, LoopNo, DENSE_RANK() OVER(PARTITION BY LoopNo ORDER BY WordID) RowNo
		FROM CTE 
	) T
	ORDER BY RowNo, LoopNo
	RETURN
END;
GO


Использование:
USE test; --replace with your database name

;WITH AllSentences AS
(
	SELECT ID, [Name]
	FROM Account 
)
SELECT a.ID, a.[Name], b.NewSentence
FROM AllSentences a
CROSS APPLY udf_SentenceToMulti(a.ID, a.[Name]) b


Пример результата:
1	This is a sentence	This
1	This is a sentence	Thisis
1	This is a sentence	Thisisa
1	This is a sentence	Thisisasentence
1	This is a sentence	is
1	This is a sentence	isa
1	This is a sentence	isasentence
1	This is a sentence	a
1	This is a sentence	asentence
1	This is a sentence	sentence
2	This is another sentence	This
2	This is another sentence	Thisis
2	This is another sentence	Thisisanother
2	This is another sentence	Thisisanothersentence
2	This is another sentence	is
2	This is another sentence	isanother
2	This is another sentence	isanothersentence
2	This is another sentence	another
2	This is another sentence	anothersentence
2	This is another sentence	sentence
...