4

我有以下表格:

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

示例 putput(EntryID、TagID):

1 2
1 4
1 5
2 3
2 4
2 5
etc...

Tags
----
TagID
Name

示例输出:

1 peas
2 corn
3 carrots
...etc.

我想恢复每个条目的标签列表,但作为标签用逗号分隔的一行。

例如我想看到这个:

EntryID     TagsCommaDelimited
-------     ------------------
1           corn, peas, carrots
2           barley, oats
...and so on 

所以我需要列出每个 EntryID 及其对应的逗号分隔标签列表。

我从如下所示的内容表中选择:

Content
--------
ID   -(which is in essence the EntryID, they didn't make it consistent)
Description
..etc.

这是我尝试过的,但我的语法没有运气:

declare @tagsCommaDelimited varchar (200) 
set @tagsCommaDelimited = '';


With AllEntryTags_CTE(Name, EntryID )
as
(
    select Tags .Name,
           entryTags.EntryID 
    from  EntryTag entryTags
    join Tags on tags.Id = entryTags.TagID
    group by entryTags.EntryID, tags.Name, entryTags.TagID 
),

TagsByEntryCommaDelimited_CTE( EntryID, CommaDelimitedTags)
as
(
    select  distinct allTags.EntryID,
            (select @tagsCommaDelimited from ( select @tagsCommaDelimited = coalesce (case when @tagsCommaDelimited = '' then allTags.Name
                                                                                      else @tagsCommaDelimited + ',' + allTags.Name end ,'') as CommaDelimitedTags
    from  AllEntryTags_CTE allTags  
)

select EntryID, CommaDelimitedTags from TagsByEntryCommaDelimited_CTE

- - - - - - - - - - - - - -更新 - - - - - - - - - - - ------------

现在我和 gotgn 一起去测试

我现在遇到的问题是,我试图在我的最终选择语句中使用最后一个 CTE 来获取以逗号分隔的标签名称列表。但它说我的语法不正确:

;WITH CommaDelimitedTagIDs AS
(
    SELECT DISTINCT EntryID,
    (SELECT SUBSTRING((SELECT ',' + CAST(TagID AS NVARCHAR(10)) 
                       FROM EntryTag AS T1 WHERE T1.EntryID=T2.EntryID 
                       ORDER BY TagID 
                       FOR XML PATH('')),2,200)) AS commaDelimitedTagIDs
    FROM EntryTag T2 
),

CommaDelimittedTagNames_CTE (EntryID, CommaDelimitedTagNames) as
( 
    SELECT EntryID, (SELECT SUBSTRING((SELECT ',' + Name 
                     FROM Tags 
                     WHERE commaDelimitedTagIDs LIKE '%'+CAST(ID AS NVARCHAR(5))+'%'  
                     ORDER BY ID FOR XML PATH('')),2,200) AS CSV) 
    FROM CommaDelimitedTagIDs
)

--select EntryID, CommaDelimitedTagNames from CommaDelimittedTagNames_CTE


SELECT  Title,
        [Description],
        DateSyndicated,
        DateUpdated,
        1, 
        CAST([Text] AS NVARCHAR(MAX)),
        Author,
        (select CommaDelimitedTagNames from CommaDelimittedTagNames_CTE) as tagNamesCommaDelimited 
 FROM Content
 Join CommaDelimittedTagNames_CTE tags on tags.EntryID = Content.ID
 group by ID, Title, [Description], 
          DateSyndicated, DateUpdated, 
          CAST(subtextContent.[Text] AS NVARCHAR(MAX)), Author 

也试过这种方式,没有运气

  Select
    ....other fields
    (select CommaDelimitedTagNames from CommaDelimittedTagNames_CTE tagNames 
     join subContent on subContent.ID = tagNames.EntryID) as tags 
  FROM Content as subContent

好的,我想您不能加入,我不得不将其更改为 Where。不知道为什么,但这现在有效:

   Select
    ....other fields
    (select CommaDelimitedTagNames from CommaDelimittedTagNames_CTE tagNames 
     where Content.ID = tagNames.EntryID) as tags 
  FROM Content 
4

2 回答 2

14
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

剖析查询

主查询执行 a group by,因此每个EntryID.

该列TagsCommaDelimited是使用相关子查询创建的。

在 SQL Serverfor xml path中用于创建查询结果的 XML 表示。您可以通过使用列别名和参数来很好地控制 XML 的创建方式pathroot

相关子查询中的连接值', '+T.Name将没有列名和空参数来for xml path('')创建完全没有任何标签的 xml。只会返回一个文本值。

当您添加typefor xml查询时,数据类型将为XML.

要从 XML 中获取值,您应该使用该value()方法。你可以转换成一个字符串,但是如果你这样做了,例如你会&在任何你使用过的地方进入字符串&

函数中的第一个参数value()是用于获取所需值的 xQuery 表达式。用于text()指定您只需要当前元素的值。[1]告诉 SQL Server 你想要找到第一个文本节点(你这里只有一个),但它仍然是必要的。

查询创建的字符串在for xml字符串开头有一个额外的逗号和一个空格,需要删除。在这里,我使用 XQuery 函数substring来获取除前两个字符之外的所有内容。

第二个参数value()指定应返回的数据类型。

于 2013-01-17T07:49:53.653 回答
1
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
于 2013-01-17T08:20:38.027 回答