До SQL Server 2017, когда string_agg
был наконец-то представлен как встроенная функция, распространенным методом объединения строк из разных строк было использование комбинации stuff
и for xml path('')
как показано здесь .
Теперь давайте создадим и заполним примеры таблиц ( Пожалуйста сохраните нам этот шаг в ваших будущих вопросах):
CREATE TABLE AuthorMaster
(
id int,
Name char(3)
);
INSERT INTO AuthorMaster (ID, Name) VALUES
(1, 'ABC'),
(2, 'XYZ'),
(3, 'PQR');
CREATE TABLE Books
(
ID int,
BookName varchar(100),
AuthorIds varchar(100)
);
INSERT INTO Books (ID, BookName, AuthorIds) VALUES
(1, 'MATHEMATICS', '2,3'),
(2, 'Briar Queen', '1,3');
Проблема с этим дизайном заключается в том, что вместо создания таблицы мостов BookToAuthor
для создания отношения «многие ко многим» разработчик базы данных использовал ужасную идею и решил сохранить идентификаторы авторов в виде строки с разделителями вбаза данных.( Почему это такая ужасная идея? )
Чтобы преодолеть это, нам нужно разбить эту строку с разделителями.Увы, до SQL Server 2016, когда string_split
был наконец введен, вам нужно было использовать пользовательскую функцию для разделения строки с разделителями.
Аарон Бертран опубликовалСтатья под названием Разделить строки правильным способом - или следующим лучшим способом в 2012 году, где он сравнивает различные функции разделения строк.В этом ответе я использовал один из его примеров из этой статьи - функцию SplitStrings_XML
:
CREATE FUNCTION dbo.SplitStrings_XML
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
Итак, теперь у нас есть пример данных и функция разделения строк, давайте перейдем к запросу.Используя запрос агрегации строк по именам авторов, где идентификаторы находятся в столбце AuthorIds, и перекрестное применение для привязки этого к таблице книг. Вот запрос, который я создал:
SELECT ID,
BookName,
AuthorsNames
FROM Books
CROSS APPLY
(
SELECT STUFF(
(
SELECT ','+ Name
FROM AuthorMaster
WHERE Id IN
(
SELECT Item
FROM dbo.SplitStrings_XML(AuthorIds, ',')
)
FOR XML PATH('')
), 1, 1, '') As AuthorsNames
) As Names
И вот его результаты:
ID BookName AuthorsNames
1 MATHEMATICS XYZ,PQR
2 Briar Queen ABC,PQR