2012-01-25 12 views
27

मैंने सोचा कि मुझे समझ में आया कि बाहरी कैसे काम करता है, लेकिन मेरे पास ऐसी स्थिति है जो काम नहीं कर रही है, और मुझे 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) 

इस विशेष मामले में, achievement तालिका "मास्टर" तालिका है और इसमें वह जानकारी होगी जो मैं हमेशा देखना चाहता हूं। 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) शो किया जा रहा है नल मूल्यों के साथ मैं इस प्रकार की क्वेरी से अपेक्षा करता हूं। यही वह है जिसे मैं देखने की उम्मीद कर रहा हूं:

+----+-------------------------------+--------------+---------+ 
| 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" खंड में लाकर एक इंटर्न जॉइन (हमेशा मिलान करना चाहिए) का अर्थ होगा जो आप नहीं चाहते हैं ... मैं सहसंबंध रखने के लिए हमेशा बाएं टेबल alias.field = right table alias.field को दिखाने का प्रयास करता हूं। स्पष्ट ... फिर, आधार मापदंड आप पहली बार मेज से चाहते हैं जहां खंड लागू .. की तरह

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) 

सूचना आम आईडी और खेल आईडी के आधार पर के बीच "एक" और "गा" सीधा संबंध कुछ मूल्य, लेकिन फिर विशिष्ट गेमर पर tacked। जहां खंड केवल विशिष्ट खेल के आधार पर उपलब्धि के बाहरी स्तर पर परवाह करता है।

+1

आपके उत्तर के बीच फाड़ा गया था और एक @ बेनोइट ने दिया (आप दोनों को उत्थान मिला), लेकिन "सर्वोत्तम प्रथाओं" की आपकी स्पष्टीकरण और चर्चा यही कारण है कि मैंने यहां चेकमार्क लगाया। धन्यवाद! – TheIcemanCometh

9

WHERE खंड में आप कुछ पंक्तियों को त्याग देते हैं जो बाएं जॉइन नल मानों से भरे होंगे। आप जॉइन क्लॉज के अंदर 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 

याद रखें कि में शामिल होने के लिए किया जाता है, और इस समय, शून्य मान यदि शर्त पूरी नहीं की जा सकती है; तो where फ़िल्टर लागू होता है।

+0

मुझे इस जवाब को सभी उत्तरों के बीच पसंद है मैंने कभी भी –

1

यह इस लाइन की वजह से है:

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

हैं gamerachievement अर्जित नहीं किया है, ga.gamer_id मूल्य NULL हो जाएगा और WHERE हालत के लिए योग्य नहीं।

0

मेरा अनुमान है कि जहां क्लॉज आपके वांछित परिणामों को फ़िल्टर कर रहा है, इसे बाएं जुड़ने में ले जाया जा सकता है।

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

असल में यह प्रत्येक उपलब्धि के लिए कुल मूल्यों के साथ एक पंक्ति प्रदर्शित करेगा जिसमें आईडी 1480656849 नहीं है। – Benoit

3

WHERE संपूर्ण परिणाम सेट से फ़िल्टर परिणाम खंडित करता है।यदि आप केवल JOIN पर फ़िल्टर लागू करना चाहते हैं, तो आप अभिव्यक्ति को ON खंड में जोड़ सकते हैं।

निम्न क्वेरी में, मैंने फ़िल्टर अभिव्यक्ति को स्थानांतरित कर दिया है जो WHERE क्लॉज से ऑन क्लॉज में शामिल तालिका (ga.gamer_id =) पर लागू होता है। यह अभिव्यक्ति को उन पंक्तियों को फ़िल्टर करने से रोकता है जहां gamer_achievement मान पूर्ण हैं।

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) 
संबंधित मुद्दे