4

我正在使用 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

因为这个人是唯一一个什么时候加胡萝卜也加盐的人。

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

4

3 回答 3

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玩。

于 2012-10-31T17:33:37.890 回答
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 ;
于 2012-10-31T18:27:08.630 回答
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
于 2012-10-31T17:25:07.000 回答