我有以下表格:
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
--------------------------- UPDATE ------------------- ---------------
现在我和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
答案 0 :(得分:13)
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
解析查询
主查询执行group by
,因此每个EntryID
只能获得一行。
使用相关子查询创建列TagsCommaDelimited
。
在SQL Server中for xml path
用于创建查询结果的XML表示。通过使用列别名以及path
和root
的参数,您可以很好地控制XML的创建方式。
核心化子查询中的连接值', '+T.Name
将没有列名,而for xml path('')
的空参数将创建没有任何标记的xml。只返回一个文本值。
将type
添加到for xml
查询时,数据类型将为XML
。
要从XML中获取值,您应该使用value()
方法。您可以强制转换为字符串,但如果您这样做,那么您将使用&
在字符串中获取&
。
value()
函数中的第一个参数是用于获取所需值的xQuery表达式。使用text()
指定您只需要当前元素的值。 [1]
告诉SQL Server您希望找到第一个文本节点(此处只有一个),但仍然需要。
for xml
查询创建的字符串在字符串的开头有一个额外的逗号和一个空格,需要删除。在这里,我使用XQuery函数substring
来获取除前两个字符之外的所有内容。
value()
的第二个参数指定应返回的数据类型。
答案 1 :(得分: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