在MSSQL中的Books表的选择查询中,从AuthorMaster表中获取逗号分隔的AuthorName

时间:2019-04-02 08:58:28

标签: sql-server sql-server-2012

我有两个表:1. AuthorMaster和2. Books

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 个答案:

答案 0 :(得分:1)

在SQL Server 2017之前,string_agg最终作为内置函数引入时, 连接不同行中的字符串的常见方法是使用here所示的stufffor 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桥接表来创建多对多关系, 数据库设计者使用了一个糟糕的主意,决定将作者ID作为分隔字符串存储在数据库中。 (Why is this such a terrible idea?

要克服此问题,我们需要分割此定界字符串。 las,在SQL Server 2016之前,当最终引入string_split时,您必须使用用户定义的函数来分隔定界字符串。
Aaron Bertrand在2012年发表了一篇名为Split strings the right way – or the next best way的文章,他比较了不同的字符串拆分功能。 我在该答案中使用了他的文章中的一个示例-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

现在,我们有了示例数据和字符串拆分功能,让我们开始查询。在作者的名字上使用字符串聚合查询,这些ID在AuthorIds列中,然后交叉应用以将其绑定到books表中, 这是我想出的查询:

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