在sql表中精确匹配标记/标签列表
我需要获取与标签或标记列表完全匹配的行。我有一个标签主表、带有标签FK的ContentLabels表和一个内容表 内容表: Id、名称、客户Id 标签表:Id,文本 ContentLabels表: 内容ID,LabelId 我有一个标签列表(任意数量的标签),我希望在从sql查询数据时完全匹配这些标签。我在某处尝试了以下解决方案:在sql表中精确匹配标记/标签列表,sql,sql-server,Sql,Sql Server,我需要获取与标签或标记列表完全匹配的行。我有一个标签主表、带有标签FK的ContentLabels表和一个内容表 内容表: Id、名称、客户Id 标签表:Id,文本 ContentLabels表: 内容ID,LabelId 我有一个标签列表(任意数量的标签),我希望在从sql查询数据时完全匹配这些标签。我在某处尝试了以下解决方案: DECLARE @LabelTexts NVARCHAR(MAX) = 'coke,edible,chips'; DECLARE @Labels AS TABLE(
DECLARE @LabelTexts NVARCHAR(MAX) = 'coke,edible,chips';
DECLARE @Labels AS TABLE(
[Text] NVARCHAR(128)
);
INSERT INTO @Labels ([Text])
SELECT [Data] FROM StrSplit(@LabelTexts, ',')
DECLARE @LabelsCount INT = (SELECT COUNT(*) FROM @Labels);
SELECT c.[CustomerID] ,
c.[ContentID] AS Id ,
c.ClusterId
FROM ContentLabels cbl
JOIN Labels l ON l.ClusterId = cbl.LabelClusterId
JOIN Content c ON c.ClusterId = cbl.ContentClusterId
GROUP BY c.[CustomerID],
c.[ContentID],
c.ClusterId
HAVING
COUNT(DISTINCT CASE WHEN l.[Text] IN( 'coke','chips','edible') THEN l.[Text] END)=@LabelsCount
AND COUNT(DISTINCT CASE WHEN l.[Text] NOT IN( 'coke','chips','edible') THEN l.[Text] END) = 0;
当执行上述查询时,它工作得非常好,因为我在Having子句中的in子句中以硬形式添加了标记/标签。但当我在HAVING子句中添加以下查询时:
HAVING COUNT(DISTINCT CASE WHEN l.[Text] IN(SELECT * FROM @Labels) THEN l.[Text] END)=@LabelsCount
AND COUNT(DISTINCT CASE WHEN l.[Text] NOT IN(SELECT * FROM @Labels) THEN l.[Text] END) = 0;
我得到以下错误:
无法对包含聚合或子查询的表达式执行聚合函数
这只是因为
从@Labels中选择*
在有从句时。花了好几个小时寻找解决方案,但没有成功。任何帮助都是值得称赞的。请像以下那样使用操作员:
HAVING COUNT(DISTINCT CASE WHEN ',' + @LabelTexts + ',' LIKE '%,' + l.[Text] + ',%' THEN l.[Text] END) = @LabelsCount
AND COUNT(DISTINCT CASE WHEN ',' + @LabelTexts + ',' NOT LIKE '%,' + l.[Text] + ',%' THEN l.[Text] END) = 0;
您需要左键加入所需的匹配项,然后执行条件聚合 这种类型的查询称为“无余数的关系除法”,请参见等人的相关内容
SELECT c.[CustomerID] ,
c.[ContentID] AS Id ,
c.ClusterId
FROM ContentLabels cbl
JOIN Labels l ON l.ClusterId = cbl.LabelClusterId
JOIN Content c ON c.ClusterId = cbl.ContentClusterId
LEFT JOIN @labels labelMatches ON labelMatches.[Text] = l.[Text]
GROUP BY c.[CustomerID],
c.[ContentID],
c.ClusterId
HAVING
COUNT(DISTINCT labelMatches.[Text] END)=@LabelsCount
AND COUNT(CASE WHEN labelMatches.[Text] IS NULL THEN 1 END) = 0;
您可以组合使用
不退出
和分组方式
:
SELECT
c.[CustomerID]
, c.[ContentID]
, c.ClusterId
FROM Content c
JOIN ContentLabels cl
JOIN Labels l ON l.ClusterId = cl.LabelClusterId
WHERE NOT EXISTS
(
-- to filter out c.ClusterId values being related to labels NOT IN the specified list
SELECT 1
FROM ContentLabels cl2
JOIN Labels l2 ON l2.ClusterId = cl2.LabelClusterId
WHERE (l2.[Text] NOT IN(SELECT * FROM @Labels))
AND c.ClusterId = cl2.ContentClusterId
)
GROUP BY
c.[CustomerID]
, c.[ContentID]
, c.ClusterId
HAVING COUNT(DISTINCT l.[Text]) = @LabelsCount
上面看起来像是T-SQL,而不是MySQL,为什么在这里都加上标签?你不明白这个错误是怎么回事,因为它告诉了你问题所在。@Larnu我得到的解决方案是从MySql查询中得到的,我把它改成了t-Sql。是的,这个错误是可以理解的,但我不知道它的解决办法。我已经尝试连接标签,但没有成功。您不能将子查询放在聚合中,您需要将其放在其他位置。是的,但需要将该查询添加到何处。它正在对数据集进行计数,我尝试在该查询之前进行计数,并直接在having子句中应用,但没有效果。如果将
SELECT*FROM@Labels
替换为SELECT[data]FROM StrSplit(@LabelTexts,,)
,会发生什么<代码>输入(选择*..无论如何都是错误的,输入(选择[文本]…
会更符合逻辑。这不起作用,它带来了有任何标签的行。标签不完全相同。@Harry.Naeem检查这个简化的情况:代码应该可以工作。将示例数据发布到测试中。是的,它工作了,感谢解决方案就是这样。这完全按照预期工作。Giorgos Betsos answer也可以工作,但我更喜欢它这是左连接解决方案。感谢manthanks的解决方案。它正在按预期工作。