【问题标题】:Select records on join where value equals something, but also when it doesn't?在连接时选择值等于某物的记录,但当它不等于时?
【发布时间】:2013-03-03 00:14:33
【问题描述】:

我正在尝试从 2 个表中选择记录,这些表由 MySQL 中的 unique_id 列连接。

profile 包含每个玩家 1 个唯一条目。

player_current_life 包含每个玩家的许多条目,所有条目都带有player_current_life.is_dead = 1,并且可能有1 个player_current_life.is_dead = 0 条目。

如果玩家在创建新角色之前被杀并离开游戏,他们将不会拥有player_current_life.is_dead = 0。他们所有的记录都是player_current_life.is_dead = 1

我想: profile.total_player_kills + player_current_life.player_kills在哪里player_current_life.is_dead = '0'

但是

如果循环中该用户不存在player_current_life.is_dead = 0,则仅拉取profile.total_player_kills

这将循环表中的所有玩家并显示他们过去生命的总击杀数 (profile.total_player_kills),但如果他们有一个未死的角色 (player_current_life.is_dead = 0),也会拉取他们当前的生命击杀数.

到目前为止,我所拥有的只有在他们有一个在游戏中还活着的角色时才有效。

SELECT sum(profile.total_player_kills + player_current_life.player_kills) AS All_Player_Kills, profile.name AS Player_Name
FROM
  profile
LEFT OUTER JOIN player_current_life
ON profile.unique_id = player_current_life.unique_id AND player_current_life.is_dead = '0'
WHERE
  profile.total_play_time + player_current_life.play_time >= 10
GROUP BY
  profile.name

简而言之,从profileplayer_current_life 提取总击杀数,如果他们有一个还活着的角色,如果他们没有,只从profile 提取击杀数。

这是我制作的可视化表格,以更好地解释我要完成的工作。

profile (only increases when the player dies)
+-------------+-----------+--------------+
| Player_Name | unique_id | player_kills |
+-------------+-----------+--------------+
| Player1     | 12345     | 25           |
+-------------+-----------+--------------+ 
| Player2     | 67890     + 12           |
+-------------+-----------+--------------+
| Player3     | 54321     + 9            |
+-------------+-----------+--------------+

player_current_life (contains kill count not sent to "profile" where is_dead = 0)
+-------------+--------------+-----------+
| unique_id   | player_kills | is_dead   |
+-------------+--------------+-----------+
| 12345       | 8            | 0         |
+-------------+--------------+-----------+
| 12345       | 15           | 1         |
+-------------+--------------+-----------+
| 12345       | 10           | 1         |
+-------------+--------------+-----------+
| 67890       + 7            | 1         |
+-------------+--------------+-----------+
| 67890       + 5            | 1         |
+-------------+--------------+-----------+
| 54321       + 2            | 1         |
+-------------+--------------+-----------+
| 54321       + 7            | 1         |
+-------------+--------------+-----------+
| 54321       + 5            | 0         |
+-------------+--------------+-----------+

输出应该是:

玩家 1 击杀数 = 33 (25 + 8)

玩家 2 击杀数 = 12 (12 + 0)

玩家 3 击杀数 = 14 (9 + 5)

谢谢!

【问题讨论】:

标签: mysql database join


【解决方案1】:

这不是很好的做法,但如果is_dead 对活着的玩家为零,而对于死去的玩家始终为 1,那么 (1-is_dead) 将为温暖的玩家为 1,为已故的玩家为 0。

然后你可以做类似的事情

SELECT (profile.total_player_kills
    + SUM((1-is_dead) * player_kills)) AS All_Player_Kills,
    profile.name AS Player_Name
FROM
  profile
LEFT OUTER JOIN player_current_life
    ON profile.unique_id = player_current_life.unique_id
WHERE
    profile.total_play_time + player_current_life.play_time >= 10
GROUP BY
    profile.name

死者的player_kills 乘以 0,因此实际上被忽略了。

更好的方法是

SELECT (profile.total_player_kills
    + SUM( CASE WHEN is_dead = 0 THEN player_kills ELSE 0 END) AS ...

这更健壮,可以更容易地适应 is_dead 作为布尔类型。

我最好选择子选择:

SELECT profile.total_player_kills + this_life.total_player_kills AS ...

FROM profile
LEFT OUTER JOIN

    ( SELECT unique_id, SUM(CASE WHEN is_dead = '0' THEN player_kills ELSE 0 END)
      AS total_player_kills
    FROM player_current_life
    GROUP BY unique_id ) AS this_life

ON (profile.unique_id = this_life.unique_id)
WHERE ...

以上版本有一个SQLFiddle,您可以查看。

注意:我认为您的这段代码可能无法正常工作:

SELECT sum(profile.total_player_kills + ...

因为当前生命表中的每个元组都会添加一次玩家击杀总数,而不是每个玩家一次。

【讨论】:

  • 我无法更改数据的存储方式,因为这不是我的游戏。我正在为它制作一个统计模块,需要使用我得到的东西。我将使用演示表编辑我的原始帖子,这样我的问题可能更有意义。
  • 别担心,这已被理解。我的最后一个查询满足您的限制并且似乎正在工作。我正在准备它的 SQLFiddle。
  • 非常酷!我学到了一些新东西。感谢您的帮助。
【解决方案2】:

您可以在 SELECT 子句中使用 if() statement

SELECT sum(profile.total_player_kills + IF(player_current_life.is_dead = '0', player_current_life.player_kills, 0)) AS All_Player_Kills, profile.name AS Player_Name
FROM
  profile
LEFT OUTER JOIN player_current_life
ON profile.unique_id = player_current_life.unique_id 
WHERE
  profile.total_play_time + player_current_life.play_time >= 10
GROUP BY
  profile.name

【讨论】:

  • 当我尝试这种方法时,我得到的数字比预期的结果要大得多。就好像结果乘以找到is_dead=1 的次数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多