PostgreSQL - 仅在列中具有多个外观时选择

时间:2012-10-31 16:59:12

标签: sql database postgresql select

我正在使用PostgreSQL。 我有一个有3个字段的桌子 人,食谱和成分

person = creator of the recipe
recipe = the recipe
ingredient = one of the ingredients in the recipe

我想创建一个查询,这会导致每个人在每次添加胡萝卜到配方时,该人员还必须在同一配方中加入盐。

不止一个人可以创建配方,在这种情况下,添加配料的人将被记入添加配料。有时,即使是同一个人,这种成分也会被使用不止一次。

如果是这个表:

person1, rec1, carrot
person1, rec1, salt
person1, rec1, salt
person1, rec2, salt
person1, rec2, pepper
person2, rec1, carrot
person2, rec1, salt
person2, rec2, carrot
person2, rec2, pepper
person3, rec1, sugar
person3, rec1, carrot

然后我想要这个结果: PERSON1

因为这个人是唯一一个每次添加胡萝卜的人都添加了盐。

“胡萝卜只会影响结果。我只想要在他们的食谱中添加至少一根胡萝卜的人,但我不希望那些没有添加盐的人在他们所有相同的食谱中“胡萝卜加了。对不起,但我无法解释清楚。”

3 个答案:

答案 0 :(得分:1)

这个怎么样:

   SELECT DISTINCT person
     FROM tableName
    WHERE ingredient IN('carrot', 'salt')
 GROUP BY person, recipe
   HAVING SUM(CASE WHEN ingredient = 'carrot' THEN 1 ELSE -1 END) <= 0 
          AND
          COUNT(DISTINCT ingredient) > 1;

我承认我没有太多使用PostgreSql的经验,但是查询似乎给出了SQL Fiddle所需的结果(归功于@JohnWoo提供的开头)。

我已经更新了答案;之前它返回的用户只有salts作为合法的一些食谱。第二个HAVING子句过滤掉了这种情况。

更新:上一个查询返回了所有拥有至少一个配方的所有者,这些配方遵循规则(“对于每个添加的胡萝卜添加盐也是”)。但是你(似乎)实际上需要所有遵循规则的食谱。所以查询看起来像......

SELECT DISTINCT person 
  FROM tableName
 WHERE person NOT IN (   
     SELECT person
       FROM tableName
      WHERE ingredient IN('carrot', 'salt')
   GROUP BY person, recipe
     HAVING SUM(CASE WHEN ingredient = 'carrot' THEN 1 ELSE -1 END) > 0
 );

SQL Fiddle可以玩。

答案 1 :(得分:0)

尝试:

SELECT person from
(SELECT person, recipe, COUNT(DISTINCT ingredient) ingredients
 FROM tableName
 WHERE ingredient IN ('salt', 'carrot')
 GROUP BY person, recipe
 HAVING MAX(CASE WHEN ingredient = 'carrot' THEN 1 END) = 1) p
group by person
HAVING MIN(ingredients) = 2

答案 2 :(得分:0)

这似乎是关系分裂问题的一种变体。

双嵌套NOT EXISTS解决方案:

SELECT DISTINCT person
FROM tableName AS t
WHERE NOT EXISTS
      ( SELECT *
        FROM tableName AS chosen
        WHERE chosen.ingredient = 'carrot'
          AND chosen.person = t.person
          AND NOT EXISTS
              ( SELECT *
                FROM tableName AS required
                WHERE required.ingredient = 'salt'
                  AND required.recipe = chosen.recipe
                  AND required.person = chosen.person
              ) 
      ) ;

JOIN

SELECT DISTINCT 
    t.person
FROM 
        tableName AS t
    LEFT JOIN
            tableName AS chosen
        LEFT JOIN
            tableName AS required
          ON  required.ingredient = 'salt'
          AND required.recipe = chosen.recipe
          AND required.person = chosen.person
      ON  chosen.ingredient = 'carrot'
      AND chosen.person = t.person
      AND required.ingredient IS NULL
WHERE
    chosen.ingredient IS NULL ;