计算单个帖子数据浏览器中的标签数量
Posted
技术标签:
【中文标题】计算单个帖子数据浏览器中的标签数量【英文标题】:Counting the number of tags in a single post - data explorer 【发布时间】:2019-05-26 20:59:04 【问题描述】:我正在尝试编写一个查询来计算单个帖子下的标签数量。我不知何故无法将标签分成一行并计算这些标签。
Other posts 建议创建一个函数来拆分标签,但是你不能创建数据交换的函数。
这是我目前的查询,它只会给我在帖子和标签中的帖子。
SELECT p.Id, p.Title, p.Tags, t.TagName
FROM Posts as p
INNER JOIN Tags as t ON p.Id = t.Id
【问题讨论】:
请显示表格的结构。 还有一些示例数据和预期输出。 我认为标签存储为例如(您的问题):[<sql><sql-server><tsql><split><dataexplorer>]
所以您可以通过LEN(Tage)
- LEN(REPLACE(< or > FROM Tag))
获取标签计数
mel,如果我理解正确,Posts.Tags
列是一个带有标签列表的字符串。如果是这样,您将不得不将其拆分为单个令牌并使用它们加入您的Tags
表(而不是p.Id
)。但这是疯狂的猜测...尝试使用 DDL、示例数据和加速输出设置 minimal reproducible example。
@Shnugo 他们在这里使用架构data.stackexchange.com/***/query/new
【参考方案1】:
您可以使用Tags
列计算标签数量:
SELECT Id, Title, Tags, LEN(Tags) - LEN(REPLACE(Tags, '<','')) AS tag_number
FROM Posts as p
WHERE Id = 2647
SEDE Demo
【讨论】:
这很好,谢谢!你怎么知道标签是用' @melSELECT TagName FROM Tags WHERE TagName LIKE '%<%' OR TagName LIKE '%>%'
-- 0 行【参考方案2】:
这几乎是猜测,但我的魔法水晶球(和马丁史密斯)告诉我,你可能正在寻找这样的东西:
DECLARE @mokupPosts TABLE(ID INT IDENTITY, SomePost VARCHAR(250),Tags VARCHAR(250));
INSERT INTO @mokupPosts VALUES
('First post','<matlab><plot><ternary><ternplot>')
,('Second post','<powershell><java><python>')
,('Third post','<image><opencv><image-processing>');
--查询将返回每个 Post
的多行,每个标记分别。
SELECT p.*
,B.token.value('text()[1]','varchar(100)') Token
FROM @mokupPosts p
CROSS APPLY(SELECT CAST('<x>' + REPLACE(REPLACE(REPLACE(REPLACE(p.Tags,'><','||'),'<',''),'>',''),'||','</x><x>') + '</x>' AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/x') B(token);
您可以轻松地将INNER JOIN
这个Tags
直接在令牌上的现有表中并执行分组COUNT()
。
如果标签可能包含禁止字符(如&, < and >
等等),您可以使用额外的内部SELECT FOR XML PATH('')
隐式转义它们:
SELECT p.*
,B.token.value('text()[1]','varchar(100)') Token
FROM @mokupPosts p
CROSS APPLY(SELECT CAST('<x>' + REPLACE((SELECT REPLACE(REPLACE(REPLACE(p.Tags,'><','||'),'<',''),'>','') AS [*] FOR XML PATH('')),'||','</x><x>') + '</x>' AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/x') B(token);
更新:更简单的方法
注意:标签不得包含元素名称中禁止使用的字符,如&, < and >
(以及更多)!
这个查询将返回一个空元素列表as xml,只需将结束的>
替换为/>
。然后查询将使用/*
迭代所有这些并通过local-name(.)
返回它们的名称:
SELECT p.*
,B.token.value('local-name(.)','varchar(100)')AS Token
FROM @mokupPosts p
CROSS APPLY(SELECT CAST(REPLACE(p.Tags,'>','/>') AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/*') B(token)
结果和上面一样……
更新 2:我刚试过这个here
...它的工作原理:-)
【讨论】:
感谢详细的解决方案!更新 2 中的链接将我路由到一个新查询,而不是您编写的那个。请在修复后通知我,以便我查看您的操作! @mel,只需将我的查询复制到那里并使用Posts
而不是@mockupPosts
【参考方案3】:
我猜你需要这样的东西
SELECT p.Id, p.Title, p.Tags, count(t.TagName)
FROM Posts as p
INNER JOIN Tags as t ON p.Id = t.Id
group by p.Id, p.Title, p.Tags
【讨论】:
那是完全错误的。因为我们有 3 个表(帖子、帖子标签、标签)。这里是多对多的关系。 你在哪里说的?【参考方案4】:您可以使用 JOIN 来获取它
SELECT P.ID,
P.Title,
P.Tags,
COUNT(Tags) TagsCount
FROM Posts P INNER JOIN PostTags PT
ON P.Id = PT.PostId
WHERE P.ID = 53243136
GROUP BY P.ID,
P.Title,
P.Tags;
SEDE Demo
更新:
这也是另一种方式
SELECT P.ID,
P.Title,
P.Tags,
COUNT(TT.Value) - 1 TagsCount
FROM Posts P CROSS APPLY (SELECT Value FROM STRING_SPLIT(Tags, '>')) TT
WHERE P.ID = 53243136
GROUP BY P.ID,
P.Title,
P.Tags;
SEDE Demo
【讨论】:
以上是关于计算单个帖子数据浏览器中的标签数量的主要内容,如果未能解决你的问题,请参考以下文章