基本集合论思想的SQL解决方案
我有一个数据库表,如下所示:基本集合论思想的SQL解决方案,sql,select,Sql,Select,我有一个数据库表,如下所示: ╔═════════════════╦════════════╗ ║ ADVERTISEMENTID ║ CATEGORYID ║ ╠═════════════════╬════════════╣ ║ 1 ║ A ║ ║ 1 ║ C ║ ║ 2 ║ A ║ ╚═════════════════╩════════════╝ 这基本
╔═════════════════╦════════════╗
║ ADVERTISEMENTID ║ CATEGORYID ║
╠═════════════════╬════════════╣
║ 1 ║ A ║
║ 1 ║ C ║
║ 2 ║ A ║
╚═════════════════╩════════════╝
这基本上意味着:
- 广告#1分为两类:A和C,以及
- 广告属于一个类别:A
有人能帮忙吗?这个问题有很多可能的解决方案,但我使用的是在
HAVING
子句中过滤结果
SELECT advertisementID
FROM TableName
GROUP BY advertisementID
HAVING SUM(CASE WHEN CategoryID IN ('A','B','C') THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0
SUM(CASE WHEN CategoryID IN ('A','B','C') THEN 1 ELSE 0 END) > 0
它所做的是计算与给定列表匹配的类别ID
。它应该至少具有列表中的一个匹配项。另一个,
SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0
它统计给定列表中不匹配的所有
类别ID
。这一次,该值应为零,以便对结果进行过滤。使用SQLFIDLE中@JW的模式,另一种解决方案是:
SELECT matchacat.advertisementID
FROM (select distinct advertisementID
from TableName
where CategoryID in ('A', 'D')) AS matchacat
LEFT JOIN
(select distinct advertisementID
from TableName
where not CategoryID in ('A', 'D'))AS notmatch
ON (matchacat.advertisementID = notmatch.advertisementID)
WHERE notmatch.advertisementID is null
因此,获取至少与一个cat匹配的ads集,然后获取具有不匹配cat的ads集,并使用外部联接从第一个集合中删除第二个集合。这就是所谓的集合内集合问题。我认为找到任何类别匹配的最佳方法是以下方法:
select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having sum(case when categoryid = 'A' then 1 else 0 end) > 0 or
sum(case when categoryid = 'B' then 1 else 0 end) > 0 or
sum(case when categoryid = 'C' then 1 else 0 end) > 0
换句话说,这是通过advertisementid
进行聚合,并对每个类别值进行单独比较。sum()。或
表示其中任何一项都必须为真
对于子集关系,我再添加一个子句来计算不匹配项:
select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having (sum(case when categoryid = 'A' then 1 else 0 end) > 0 or
sum(case when categoryid = 'B' then 1 else 0 end) > 0 or
sum(case when categoryid = 'C' then 1 else 0 end) > 0
) and
sum(case when categoryid in ('A', 'B', 'C') then 0 else 1 end) = 0
我喜欢这种方法的原因是因为它很有表现力。如果我们将或
更改为和
,则我们要求所有三个类别:
select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having sum(case when categoryid = 'A' then 1 else 0 end) > 0 and
sum(case when categoryid = 'B' then 1 else 0 end) > 0 and
sum(case when categoryid = 'C' then 1 else 0 end) > 0
如果我们想从集合中至少找到两个匹配项,我们可以添加count(distinct)
:
等等。非常感谢您的详细回复JW!实际上,我正在寻找一些更简单的东西,可以移植到JPQL(Java Persistence API)。你能简单地描述一下你暗示的其他可能的解决方案吗?@balteo其他解决方案正在使用EXISTS
,JOIN
。我能知道我的答案中缺少什么吗?我的意思是,不接受它没有什么错,但也许我需要一些解释,这样我才能改进我的答案。我也在考虑这个问题,但您显示的第一个查询的问题是,它应该在列表上显示所有的类别ID
(我认为,通过理解给出的示例,用户不希望看到)这与从t中选择ADVERTISEMENTID非常相似,其中CategoryID在('A','B','C')组中,通过ADVERTISEMENTID具有COUNT(DISTINCT CategoryID)=3,对吗?@JW。非常感谢。问题是寻找一个严格的子集关系。呵呵,也许OP没有更好地解释主题+1
select ADVERTISEMENTID
from t
group by ADVERTISEMENTID
having (sum(case when categoryid = 'A' then 1 else 0 end) > 0 or
sum(case when categoryid = 'B' then 1 else 0 end) > 0 or
sum(case when categoryid = 'C' then 1 else 0 end) > 0
) and
count(distinct categoryid) >= 2