3

我有一个如下的数据库表:

╔═════════════════╦════════════╗
║ ADVERTISEMENTID ║ CATEGORYID ║
╠═════════════════╬════════════╣
║               1 ║ A          ║
║               1 ║ C          ║
║               2 ║ A          ║
╚═════════════════╩════════════╝

这基本上意味着:

  • 广告#1属于两类:AC以及
  • 广告#2属于一类:A

假设用户传递了(A,B,C)可能类别的参数。这里两个广告都匹配,因为可能类别的集合包含广告#1的所有类别,而可能类别的集合包含广告#2的所有类别。

但是,如果用户将另一组可能的类别作为参数传递,例如 ( A,D )。这里只有广告#2匹配,而广告#1不匹配,因为可能的类别集不包含#1的所有类别。

现在我不确定如何在 SQL 中表达这一点,即构建一个 SQL 查询,该查询从给定可能类别 ID 的参数的表中检索不同的广告 ID。

有人可以帮忙吗?

4

3 回答 3

3

这个问题有很多可能的解决方案,但我使用的是通过过滤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

它的作用是计算CategoryID给定列表中的匹配项。它应该在列表中至少有一个匹配项。另一个,

SUM(CASE WHEN CategoryID NOT IN ('A','B','C') THEN 1 ELSE 0 END) = 0

它计算CategoryID给定列表中所有不匹配的内容。这一次,它的值应该为零,以便对结果进行过滤。

于 2013-03-29T11:47:58.033 回答
2

这就是所谓的集合内集合问题。我认为在任何类别中找到匹配项的最佳方法是以下方法:

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()陈述正在计算它存在的数量。or就是说这些中的任何一个都必须是真的。

对于子集关系,我再添加一个子句来计算不匹配项:

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

我喜欢这种方法的原因是因为它很有表现力。如果我们将 更改orand,那么我们要求所有三个类别:

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)

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

等等。

于 2013-03-29T12:29:41.043 回答
1

在 sqlfiddle 中使用来自 @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

因此,获取至少匹配一只猫的广告集,然后获取具有不匹配猫的广告集,并使用外连接从第一集中删除第二集。

于 2013-03-29T12:08:17.400 回答