【问题标题】:Apply different independent filters to the same column in a GROUP BY将不同的独立过滤器应用于 GROUP BY 中的同一列
【发布时间】:2020-01-20 22:47:29
【问题描述】:

我有 2 张桌子,playersstats

players 有一个id 和一个name,而表stats 看起来像这样:

id  | Player    | Stat           | Value
1   | 0000001   | Wins           |     5
2   | 0000001   | Loses          |     6
3   | 0000001   | Jumps          |   156
4   | 0000001   | Shots          |   580
5   | 0000002   | Wins           |    15
6   | 0000002   | Loses          |     2
7   | 0000002   | Jumps          |   530
8   | 0000002   | Shots          |  1704

我想过滤符合多个条件的玩家,例如,获胜次数超过 5 次但跳跃次数少于 200 次的玩家。

我试过了

SELECT players.name
FROM players
LEFT JOIN stats
  ON stats.player = players.id
WHERE (stats.stat = "Wins" AND stats.value > 5)
  AND (stats.stat = "Jumps" AND stats.value < 200)
GROUP BY players.id

但它什么也不返回,因为GROUP BYWHERE 之后。 我也尝试过使用OR

SELECT players.name
FROM players
LEFT JOIN stats
  ON stats.player = players.id
WHERE (stats.stat = "Wins" AND stats.value > 5)
   OR (stats.stat = "Jumps" AND stats.value < 200)
GROUP BY players.id

但在这种情况下,它会返回符合任何条件的玩家,而我只想要同时符合这两个条件的玩家。在这个具体的例子中,它应该只返回带有id0000001的播放器。

我知道我可以为每个不同的统计数据使用不同的LEFT JOIN,但事实是实际表格很大并且有大量不同的统计数据,所以我不认为这是一个选择,因为它会非常慢。

【问题讨论】:

  • 如果没有 PRIMARY KEY,事情可能会变得非常棘手
  • 欢迎来到 EAV 模式的丑陋世界。

标签: mysql sql left-join where-clause entity-attribute-value


【解决方案1】:

无需聚合。您可以使用两个内部连接来执行此操作,每个条件一个:

SELECT p.name
FROM player p
INNER JOIN stats s1 ON s1.player = p.id AND s1.stat = 'Wins' AND s1.value > 5
INNER JOIN stats s2 ON s2.player = p.id AND s2.stat = 'Jumps' AND s2.value < 200

使用stats(player, stat, value) 上的索引,这应该是一个有效的选择。

【讨论】:

  • 更好的索引:完全摆脱id,然后使用PRIMARY KEY(player, stat)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
相关资源
最近更新 更多