Select back a comma delimited list grouped by an ID

前端 未结 2 1402
渐次进展
渐次进展 2020-12-03 09:42

I\'ve got the following tables:

EntryTag
---------
EntryID
TagID

Example putput (EntryID, TagID):

1 2
1 4
1 5
2 3
2 4
2 5
e         


        
相关标签:
2条回答
  • 2020-12-03 09:42
    select ET1.EntryID,
           (
           select ', '+T.Name
           from Tags as T
             inner join EntryTag as ET2
               on T.TagID = ET2.TagID
           where ET1.EntryID = ET2.EntryID
           for xml path(''), type
           ).value('substring(text()[1], 3)', 'varchar(max)') as TagsCommaDelimited
    from EntryTag as ET1
    group by ET1.EntryID
    

    Dissecting the query

    The main query does a group by so you only get one row for each EntryID.

    The column TagsCommaDelimited is created with a correlated subquery.

    In SQL Server for xml path is used to create a XML representation of a query result. You have good control over how the XML is created by using column aliases and the parameters to path and root.

    The concatenated value ', '+T.Name in the corelated subquery will not have a column name and the empty parameter to for xml path('') creates the xml without any tags at all. There will be only one text value returned.

    When you add type to a for xml query the data type will be XML.

    To get a value out of a XML you should use the value() method. You could cast to a string but if you did that you would for instance get & in the string wherever you have used &.

    The first parameter in the value() function is the xQuery expression used to get the value you want. Use text() to specify that you only want the value for the current element. [1] is telling SQL Server that you want the first text node found (you only have one here) but it is still necessary.

    The string created by the for xml query has an extra comma and a space at the beginning of the string and that needs to be removed. Here I use the XQuery function substring to get everything but the first two characters.

    The second parameter to value() specifies the datatype that should be returned.

    0 讨论(0)
  • 2020-12-03 09:46
    DECLARE @TableOne TABLE
    (
        EntryID INT,
        TagID INT
    )
    
    DECLARE @TableTwo TABLE
    (
        TagID INT,
        Name NVARCHAR(100)
    )
    
    INSERT INTO @TableOne (EntryID,TagID)
    VALUES  (1,2)
           ,(1,4)
           ,(1,5)
           ,(2,3)
           ,(2,4)
           ,(2,1)
    
    INSERT INTO @TableTwo (TagID,Name)
    VALUES  (1,'Daniel')
           ,(2,'Samuel')
           ,(3,'Petkov')
           ,(4,'Ivan')
           ,(5,'Jack')
    
    /* 
        In this CTE we are going to format the values int the folowing way:
    
        1   2,4,5
        2   1,3,4
    
        Or for eaech EntryIDs, we will have all its TagIDs 
    
    */
    ;WITH CTE AS
    (
        SELECT DISTINCT EntryID
              ,(SELECT SUBSTRING((SELECT ',' + CAST(TagID AS NVARCHAR(10)) FROM @TableOne AS T1 WHERE T1.EntryID=T2.EntryID ORDER BY TagID FOR XML PATH('')),2,200)) AS CSVTags
        FROM @TableOne T2
    
    )
    /*
        Here we are replacing the EntryIDs with their names from the @TableTwo:
    */
    SELECT EntryID
          ,(SELECT SUBSTRING((SELECT ',' + Name FROM @TableTwo WHERE CSVTags LIKE '%'+CAST(TagID AS NVARCHAR(5))+'%' ORDER BY TagID FOR XML PATH('')),2,200) AS CSV) 
    FROM CTE
    
    0 讨论(0)
提交回复
热议问题