我以为我理解左外连接是如何工作的,但是我的情况不起作用,而且我不能100%确定我的查询结构是否不正确,或者是否是数据问题。< / p>
对于后台,我有以下MySQL表结构:
mysql> describe achievement;
+-------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------+-------+
| id | varchar(64) | NO | PRI | NULL | |
| game_id | varchar(10) | NO | PRI | NULL | |
| name | varchar(64) | NO | | NULL | |
| description | varchar(255) | NO | | NULL | |
| image_url | varchar(255) | NO | | NULL | |
| gamerscore | smallint(5) unsigned | NO | | 0 | |
| hidden | tinyint(1) | NO | | 0 | |
| base_hidden | tinyint(1) | NO | | 0 | |
+-------------+----------------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
和
mysql> describe gamer_achievement;
+----------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+-------+
| game_id | varchar(10) | NO | PRI | NULL | |
| achievement_id | varchar(64) | NO | PRI | NULL | |
| gamer_id | varchar(36) | NO | PRI | NULL | |
| earned_epoch | bigint(20) unsigned | NO | | 0 | |
| offline | tinyint(1) | NO | | 0 | |
+----------------+---------------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
至于数据,这就是我在这里填充的内容(为简洁起见,仅包括相关的列):
+----+------------+------------------------------+
| id | game_id | name |
+----+------------+------------------------------+
| 1 | 1480656849 | Cluster Buster |
| 2 | 1480656849 | Star Gazer |
| 3 | 1480656849 | Flower Child |
| 4 | 1480656849 | Oyster-meister |
| 5 | 1480656849 | Big Cheese of the South Seas |
| 6 | 1480656849 | Hexic Addict |
| 7 | 1480656849 | Collapse Master |
| 8 | 1480656849 | Survivalist |
| 9 | 1480656849 | Tick-Tock Doc |
| 10 | 1480656849 | Marathon Mogul |
| 11 | 1480656849 | Millionaire Extraordinaire |
| 12 | 1480656849 | Grand Pearl Pooh-Bah |
+----+------------+------------------------------+
12 rows in set (0.00 sec)
和
+----------------+------------+--------------+---------+
| achievement_id | game_id | earned_epoch | offline |
+----------------+------------+--------------+---------+
| 1 | 1480656849 | 0 | 1 |
| 2 | 1480656849 | 0 | 1 |
| 3 | 1480656849 | 0 | 1 |
| 4 | 1480656849 | 1149789371 | 0 |
| 7 | 1480656849 | 1149800406 | 0 |
| 8 | 1480656849 | 0 | 1 |
| 9 | 1480656849 | 1149794790 | 0 |
| 10 | 1480656849 | 1149792417 | 0 |
+----------------+------------+--------------+---------+
8 rows in set (0.02 sec)
在这种特殊情况下,achievement
表是“主”表,将包含我一直想看的信息。 gamer_achievement
表仅包含实际获得的成就的信息。对于任何特定游戏玩家的任何特定游戏,gamer_achievement
表中可以有任意数量的行 - 如果没有为该游戏获得任何成就,则包括无行数。例如,在上面的示例数据中,尚未获得ID为5,6,11和12的成就。
我目前所写的是
select a.id,
a.name,
ga.earned_epoch,
ga.offline
from achievement a
LEFT OUTER JOIN gamer_achievement ga
ON (a.id = ga.achievement_id and a.game_id = ga.game_id)
where ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024'
and a.game_id = '1480656849'
order by convert (a.id, unsigned)
但这仅返回实际获得的成就的完整信息 - 右侧表(gamer_achievement
)中未实现的成就信息未显示NULL值,正如我所期望的那样查询类型。这是我期待看到的:
+----+-------------------------------+--------------+---------+
| id | name | earned_epoch | offline |
+----+-------------------------------+--------------+---------+
| 1 | Cluster Buster | 0 | 1 |
| 2 | Star Gazer | 0 | 1 |
| 3 | Flower Child | 0 | 1 |
| 4 | Oyster-meister | 1149789371 | 0 |
| 5 | Big Cheese of the South Seas | NULL | NULL |
| 6 | Hexic Addict | NULL | NULL |
| 7 | Collapse Master | 1149800406 | 0 |
| 8 | Survivalist | 0 | 1 |
| 9 | Tick-Tock Doc | 1149794790 | 0 |
| 10 | Marathon Mogul | 1149792417 | 0 |
| 11 | Millionaire Extraordinaire | NULL | NULL |
| 12 | Grand Pearl Pooh-Bah | NULL | NULL |
+----+-------------------------------+--------------+---------+
12 rows in set (0.00 sec)
我在这里缺少什么?根据我的理解,基本查询对我而言,但我显然错过了一些关键信息。
答案 0 :(得分:16)
许多人已经回答了,但我也会尝试,希望能提供更多的澄清。我如何总是解释它(你可以检查我用LEFT连接回复的许多其他帖子),我尝试列出我想要的所有内容的表(左侧...因此从左到右阅读)。然后左边加入“其他”表(右侧),无论它们之间的条件是什么......然后,当进行左连接时,对于右侧表还有其他标准,这些条件将保持该连接条件。通过将它们带入“WHERE”子句意味着INNER JOIN(必须始终匹配)这不是你想要的...我也尝试始终显示左表alias.field =右表alias.field以保持相关性clear ...然后,将where子句应用于您希望从第一个表中获得的基本条件..类似
select
a.id,
a.name,
ga.earned_epoch,
ga.offline
from
achievement a
LEFT OUTER JOIN gamer_achievement ga
ON a.id = ga.achievement_id
AND a.game_id = ga.game_id
AND ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024'
where
a.game_id = '1480656849'
order by
convert (a.id, unsigned)
通过公共ID和游戏ID值注意“a”和“ga”之间的直接关系,但随后在特定游戏玩家上加以说明。 where子句仅关注基于特定游戏的外部成就水平。
答案 1 :(得分:9)
在WHERE子句中,您将丢弃LEFT JOIN将填充NULL值的某些行。您希望将条件ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024'
放在JOIN子句中。
另一种选择是:
LEFT OUTER JOIN (SELECT * FROM gamer_achievement
WHERE ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024'
) ga
请记住,已执行连接,此时,如果无法满足条件,则会出现NULL值;然后适用where
过滤器。
答案 2 :(得分:3)
WHERE
子句过滤整个结果集的结果。如果您只想将过滤器应用于JOIN
,则可以将表达式添加到ON
子句中。
在下面的查询中,我将应用于连接表(ga.gamer_id =
)的过滤器表达式从WHERE子句移动到ON子句。这可以防止表达式过滤掉gamer_achievement值为NULL的行。
SELECT a.id,
a.name,
ga.earned_epoch,
ga.offline
FROM achievement a
LEFT OUTER JOIN gamer_achievement ga
ON ga.achievement_id = a.id
AND ga.game_id = a.game_id
AND ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024'
WHERE
a.game_id = '1480656849'
ORDER BY CONVERT(a.id, UNSIGNED)
答案 3 :(得分:1)
这是因为这一行:
where ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024'
如果gamer
未获得achievement
,则ga.gamer_id
值将为NULL
,且不符合WHERE
条件。
答案 4 :(得分:0)
我的猜测是where子句会过滤掉你想要的结果,将它移到左边的连接可能会有效。
select a.id,
a.name,
ga.earned_epoch,
ga.offline
from achievement a
LEFT OUTER JOIN gamer_achievement ga
ON (a.id = ga.achievement_id and
a.game_id = ga.game_id and
ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024' and
a.game_id = '1480656849')
order by convert (a.id, unsigned)