将集合理论思想转化为SQL

时间:2013-03-30 18:49:57

标签: mysql sql relational-division

假设我有以下数据库表:

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

给定一个作为参数传递的类别列表,比如说 A, C 我只想找到那些只属于这两个类别的广告,在上面的例子中只有广告 1 会匹配。

任何人都可以帮我翻译成SQL吗?

3 个答案:

答案 0 :(得分:2)

select advertismentid
from the_table
where categoryid in ('A', 'C')
group by  advertismentid
having count(*) = 2;

SQLFiddle:http://sqlfiddle.com/#!12/b94d6/1

这假设同一个categoryid不能多次分配给同一个adsismentid。它还将包括具有A,C和其他类别的广告。

如果您想要那些完全类别A和C的广告,您需要排除那些具有超过该类别的广告:

select advertismentid
from the_table
where categoryid in ('A', 'C')
group by  advertismentid
having count(*) = 2;
intersect
select advertismentid
from the_table
group by advertismentid
having count(*) = 2;

SQLFiddle:http://sqlfiddle.com/#!12/8901c/4
SQLFiddle还有另一个使用except而不是intersect

的解决方案

如果您的DBMS受限且无法使用exceptintersect,则可以使用此替代方法:

select t1.advertismentid
from the_table t1
where t1.categoryid in ('A', 'C')
group by t1.advertismentid
having count(*) = 2
and count(*) = (select count(*) 
                from the_table t2
                where t2.advertismentid = t1.advertismentid)

答案 1 :(得分:1)

SELECT DISTINCT advertisementid 
FROM tft t1
WHERE t1.categoryid IN ('A','C')
AND EXISTS (
  SELECT * FROM tft t2
  WHERE t2.advertisementid = t1.advertisementid
  AND t2.categoryid IN ('A','C')
  AND t2.categoryid <> t1.categoryid
  );

答案 2 :(得分:1)

好像我来晚了,但无论如何这里是我的解决方案:

SELECT advertisement
FROM   advertisement_childcare_types t1
LEFT JOIN (
       SELECT childcare_types ct
       FROM   table_childcare_types tct
       WHERE  childcare_types IN (0, 1, 3)
          ) AS mytypes
ON     t1.childcare_types = mytypes.ct
GROUP BY advertisement
HAVING SUM(IF(mytypes.ct IS NULL, -1, 1)) = 3;

您可以使用此修改版本在您的sqlfiddle中进行测试:

SELECT advertisement
FROM   advertisement_childcare_types t1
LEFT JOIN (SELECT 0 as ct UNION SELECT 1 UNION SELECT 3) AS mytypes
ON     t1.childcare_types = mytypes.ct
GROUP BY advertisement
HAVING SUM(IF(mytypes.ct IS NULL, -1, 1)) = 3;