我在SQL中有两个表,一个有项目,另一个有项目所属的类,即JOIN看起来大致如下:
Project | Category
--------+---------
Foo | Apple
Foo | Banana
Foo | Carrot
Bar | Apple
Bar | Carrot
Qux | Apple
Qux | Banana
(显然,字符串替换为较高正常形式的ID,但你明白这一点。)
我想要做的是允许过滤,以便用户可以选择任意数量的类别,结果将被过滤为属于所有选定类别的成员的项目。例如,如果用户选择类别“Apple”和“Banana”,则显示项目“Foo”和“Qux”。如果用户选择“Apple”,“Banana”和“Carrot”类别,则仅显示“Foo”项目。
我尝试的第一件事是一个简单的SELECT DISTINCT项目FROM ... WHERE Category ='Apple'和Category ='Banana',但当然这不起作用,因为Apple和Banana出现在同一列中任何常见项目的两个不同的行。
GROUP BY和HAVING对我没有任何好处,所以告诉我:是否有一种明显的方法可以做到这一点,我错过了,或者它是否真的如此复杂以至于我不得不求助于递归加入?
顺便说一句,这是在PostgreSQL中,但当然,标准SQL代码总是可行的。
答案 0 :(得分:7)
请参阅我的博客中有关效果详情的文章:
以下解决方案:
适用于任意数量的类别
COUNT
和GROUP BY
效率更高,因为它只检查一次任何项目/类别对的存在,而不计算在内。
SELECT *
FROM (
SELECT DISTINCT Project
FROM mytable
) mo
WHERE NOT EXISTS
(
SELECT NULL
FROM (
SELECT 'Apple' AS Category
UNION ALL
SELECT 'Banana'
UNION ALL
SELECT 'Carrot'
) list
WHERE NOT EXISTS
(
SELECT NULL
FROM mytable mii
WHERE mii.Project = mo.Project
AND mii.Category = list.Category
)
)
答案 1 :(得分:4)
由于项目只能在一个类别中,我们可以使用COUNT来消除这个特技:
SELECT project, COUNT(category) AS cat_count
FROM /* your join */
WHERE category IN ('apple', 'banana')
GROUP BY project
HAVING cat_count = 2
只有apple或banana类别的项目将获得1的计数,因此HAVING
子句失败。只有两个类别的项目才能获得2分。
如果由于某种原因您有类别重复,则可以使用COUNT(DISTINCT category)
之类的内容。 COUNT(*)
也可以正常工作,只有在category可以为null时才有所不同。
答案 2 :(得分:0)
另一个解决方案当然是“SELECT DISTINCT Project FROM ... AS'Wey'Apple'IN(SELECT Category FROM ... AS b WHERE a.Project = b.Project)和'Banana' IN(SELECT Category FROM ... AS b WHERE a.Project = b.Project)“,但这很快就会在计算上变得非常昂贵。我希望有更优雅的东西,你们没有失望。我包括这个主要是为了完整性,以防其他人咨询这个问题。这显然值得零分。 :)