Получите разделенное запятыми AuthorName из таблицы AuthorMaster в выбранном запросе таблицы Books в MSSQL - PullRequest
0 голосов
/ 02 апреля 2019

У меня есть две таблицы: 1. AuthorMaster и 2. Книги

AuthorMaster
----------------
ID     Name
1      ABC
2      XYZ
3      PQR

Books
----------------
ID   BookName       AuthorIds
1    MATHEMATICS    2,3
2    Briar Queen    1,3


I need output like
ID    BookName      AuthorNames
1     MATHEMATICS   XYZ, PQR
2     Briar Queen   ABC, PQR

Я пытался создать отдельную хранимую процедуру для получения имен авторов:

DECLARE @Query VARCHAR(MAX)
    declare @t table(AuthorNames varchar(max))

    SET @Query = 'DECLARE @AuthorNames VARCHAR(MAX); SELECT @AuthorNames = COALESCE( @AuthorNames + '', '', '''') + AuthorName FROM AuthorMasters WHERE AuthorId IN (' + @IDs + ') AND ISNULL(IsDelete, 0) = 0; SELECT @AuthorNames'

    INSERT INTO @t
    Execute(@Query)

    SELECT @AuthorNames = AuthorNames FROM @t

Но я не могу выполнить его в избранном зачете.

SELECT ID, BookName, <how to call sp where i can pass Books.AuthorIds?> FROM Books

1 Ответ

1 голос
/ 02 апреля 2019

До 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
...