【问题标题】:Selecting a match across multiple rows sqlite在多行 sqlite 中选择匹配项
【发布时间】:2022-01-14 21:13:10
【问题描述】:

假设我有一张名为food_prefs 的桌子,里面有朋友和他们最喜欢的食物。

id name favorite_foods
1 Amy Pizza
2 Bob Pizza
3 Chad Caviar
4 Dana Pizza
5 Dana Salad

我知道如何获取每个喜欢披萨的人的姓名,但我不清楚如何选择仅将 pizza 列为他们最喜欢的食物的人。也就是说,从上表中,我只想选择 Amy 和 Bob。

此外,如果有一个解决方案还可以选择具有多个收藏夹的名称(例如,在另一个查询中选择将pizza and salad 作为其收藏夹的每个人,这将),那就太好了。最后,如果pizza and salad 查询不仅返回了只喜欢这两种食物的人,而且还返回了只有一种最喜欢出现在该列表中的人(例如,只喜欢披萨或只喜欢沙拉的人——除了乍得之外的所有人),这可能会很有用在这个例子中)

(我发现 sqlite 文档不是最直接的,如果这是一个非常简单的问题,很抱歉!)

【问题讨论】:

  • 似乎使用grouping by name 然后选择使用having group_concat(favorite_foods) = 'Pizza' 可能会起作用(就像in ('Pizza', 'Pizza,Salad') 一样,但似乎需要在列出了所有可能的排列,看起来不太好!

标签: python sqlite group-by group-concat having


【解决方案1】:

您是对的(正如我在您的问题下方的评论中读到的),您需要聚合和 HAVING 子句中的条件。

例如,让将“披萨”列为他们最喜欢的食物的人:

SELECT name 
FROM food_prefs 
GROUP BY name
HAVING GROUP_CONCAT(favorite_foods) = 'Pizza';

但是,如果您想让那些将“披萨”和“沙拉”列为他们最喜欢的食物的人,那么:

HAVING GROUP_CONCAT(favorite_foods) = 'Pizza,Salad'

可能不起作用,因为SQLite不支持函数GROUP_CONCAT()中的ORDER BY子句,所以不能保证它会返回'Pizza,Salad'(它也可能返回'Salad,Pizza')。

在这种情况下,您需要一个更复杂的HAVING 子句:

HAVING SUM(favorite_foods IN ('Pizza', 'Salad')) = 2
   AND SUM(favorite_foods NOT IN ('Pizza', 'Salad')) = 0

或:

HAVING SUM(favorite_foods IN ('Pizza', 'Salad')) = 2
   AND COUNT(*) = 2

我假设namefavorite_foods 的组合是唯一的。

对于将“披萨”和/或“沙拉”列为他们最喜欢的食物,但他们也可能列出其他食物的人,您只需要一个 WHERE 子句和不是聚合:

SELECT DISTINCT name    
FROM food_prefs 
WHERE favorite_foods IN ('Pizza', 'Salad');

【讨论】:

  • 这一切都说得通,感谢您确认GROUP_CONCAT 的订购问题!此外,如果我们想容纳至少 1 种食物作为最爱但不在指定列表之外(例如,只是喜欢沙拉或只是喜欢披萨)
  • 第二次跟进:我上面发布的EXCEPT 解决方案和GROUP_CONCAT + HAVING SUM 解决方案之间是否存在重大性能差异?
  • @user12394023 是的,您可以根据不同的需求修改非常灵活的 HAVING 子句。对于您发布的带有 EXCEPT 的解决方案,我不得不说我不会使用扫描表两次然后在结果上应用运算符 EXCEPT 的查询。
  • 在大约 6000 个项目的实际应用程序中使用它后,似乎EXCEPT 解决方案要快得多(在我的笔记本电脑上大约是 3 倍)
  • @user12394023 快到什么程度?您的查询返回列表中包含最喜欢的食物(“披萨”、“沙拉”)且没有其他最喜欢的食物的表的所有名称,但它可以返回只有“披萨”或只有“沙拉”作为他们最喜欢的食物的人.我的查询都没有这样做。
【解决方案2】:

(此处为 OP)EXCEPT 似乎可以解决问题:

SELECT name
FROM food_prefs
WHERE favorite_foods in ('pizza', 'salad')
EXCEPT
SELECT name
FROM food_prefs
WHERE favorite_foods not in ('pizza', 'salad')

据我了解,它会在我们的选项列表中选择所有喜欢食物的names,然后删除所有在该列表之外有最爱的names(在上面的示例中,('pizza', 'salad') )。

【讨论】:

    猜你喜欢
    • 2012-10-09
    • 2011-04-18
    • 2014-07-13
    • 2013-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多