2012-01-25 18 views
27

左外部結合の仕組みを理解していると思っていましたが、動作していない状況があり、構造化されたクエリの構造が正しくない場合は100%それがデータの問題ならば。背景についてはLEFT OUTER JOINが正常に動作しない問題

が、私は次の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) 

私はここで何が欠けていますか?私が理解しているところでは、基本的な質問は私には分かりますが、明らかに重要な情報が欠落しています。

+8

+1素敵な詳細な質問..... – ManseUK

答えて

15

多くの人が回答していますが、私も試してみることにします。もう少し明確にしてください。私はいつもそれを解釈しています(そしてLEFTジョインで他の多くの投稿を確認できます)、最初からすべてを望むテーブルをリストアップしようとします(左側から...)。次に、それらの間の基準に関係なく、「その他」の表(右側)に左結合します。次に、左結合を実行し、右側の表に対して追加の基準がある場合、それらの条件はその結合条件。 "WHERE"句に入れることで、あなたが望むものでないINNER JOIN(常に一致しなければならない)を暗示することになります...私はまた、左テーブルalias.field =右テーブルalias.fieldを常に表示しようとしますクリア...次に、あなたが最初のテーブルから必要な基礎条件に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による「」と「GA」との直接的な関係のようなもの特定のゲーマーについていた。 where節は、特定のゲームに基づいた達成レベルの外側レベルのみを扱います。

+1

回答と@Benoitが与えたもの(あなたはどちらもupvotesを持っています)との間で引き裂かれましたが、 "ベストプラクティス"私はここにチェックを入れているのです。ありがとう! – TheIcemanCometh

9

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フィルタが適用されます。

+0

私はすべての答えの中でこの説明が好きです。私は今まで読んでいます –

1

それがためにこの線のだ:

where ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024' 

gamerachievementを獲得していない場合は、ga.gamer_id値はNULLこととWHERE条件の対象としません。

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) 
+1

これは必要以上の結果を表示します。 –

+0

実際には、idが1480656849でないすべての成果に対して、NULL値を持つ行が表示されます。 – Benoit

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) 
関連する問題