2012-01-25 2 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에 의해 "A"와 "조지아"사이의 직접적인 관계 같은 가치를 얻지 만, 특정 게이머에게 달라 붙었습니다. where 절은 특정 게임을 기반으로하는 업적의 외부 수준에만 관심이 있습니다.

+1

@Benoit이 준 응답과 @Benoit이주고받은 것 (둘 다 upvotes가 있음) 사이에서 찢겨졌지만 "권장 사항" 여기에 체크 표시를하는 이유입니다. 감사! – TheIcemanCometh

9

WHERE 절에서 LEFT JOIN이 NULL 값으로 채운 행을 삭제합니다. JOIN 절 안에 ga.gamer_id = 'fba8fcaa-f57b-44c6-9431-4ab78605b024' 조건을 넣으려고합니다.

또 다른 옵션은 다음과 같습니다

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' 

gamer 경우 achievement를 취득하지 않은는 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) 
관련 문제