SQL筛选同一列中的多个项目

时间:2009-08-25 18:48:10

标签: sql postgresql filter

我在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代码总是可行的。

3 个答案:

答案 0 :(得分:7)

请参阅我的博客中有关效果详情的文章:


以下解决方案:

  • 适用于任意数量的类别

  • COUNTGROUP 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)“,但这很快就会在计算上变得非常昂贵。我希望有更优雅的东西,你们没有失望。我包括这个主要是为了完整性,以防其他人咨询这个问题。这显然值得零分。 :)