Проблемы с работой LEFT OUTER JOIN

Я думал, что понял, как работают левые внешние соединения, но у меня есть ситуация, которая не работает, и я не на 100% уверен, неправильный ли способ структурирования моего запроса или проблема с данными.

Для справки, у меня есть следующие структуры таблиц 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)

В В данном конкретном случае таблица достижений является «главной» таблицей и будет содержать информацию, которую я всегда хочу видеть.Таблица gamer_achievement содержит информацию только о фактически заработанных достижениях. Для любой конкретной игры для любого конкретного игрока может быть любое количество строк в таблице gamer_achievement , включая ни одной, если в этой игре не было заработано никаких достижений. Например, в приведенном выше примере данных достижения с идентификаторами 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)

Что мне здесь не хватает? Насколько я понимаю, основной запрос ВЫГЛЯДИТ мне прямо, но мне явно не хватает какой-то важной информации.

28
задан TheIcemanCometh 25 January 2012 в 13:19
поделиться

1 ответ

Многие ответили, но я тоже попробую и, надеюсь, внесу еще несколько уточнений. Как я всегда интерпретировал это (и вы можете проверить так много других постов, на которые я ответил с помощью ЛЕВЫХ объединений), я пытаюсь перечислить таблицу, в которой я хочу все сначала (слева ... отсюда читаем слева направо). Затем левое соединение с таблицей «Другое» (правая сторона) при любых критериях между ними ... Затем, при выполнении левого соединения и при наличии дополнительных критериев относительно правой таблицы эти условия остаются с этим условием соединения. , Включение их в предложение «WHERE» подразумевает ВНУТРЕННЕЕ СОЕДИНЕНИЕ (должно всегда совпадать), что не то, что вы хотите ... Я также стараюсь всегда показывать левую таблицу 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)

Обратите внимание на прямую связь между «a» и «ga» по общему идентификатору и значения идентификатора игры, но затем привязывается к конкретному игроку. Предложение where касается только внешнего уровня достижений, основанного на конкретной игре.

17
ответ дан 28 November 2019 в 03:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: