2012-09-17 14 views
18

मैं 3 टेबल है:दो एसक्यूएल वाम कार्यभार संभाला गलत परिणाम उपज

users(id, account_balance) 
grocery(user_id, date, amount_paid) 
fishmarket(user_id, date, amount_paid) 

दोनों fishmarket और grocery टेबल अलग तिथियों और राशियों के साथ एक ही user_id के लिए अनेक गतिविधियां है या किसी भी उपयोगकर्ता के लिए कुछ भी नहीं हो सकता है ।

SELECT 
    t1."id" AS "User ID", 
    t1.account_balance AS "Account Balance", 
    count(t2.user_id) AS "# of grocery visits", 
    count(t3.user_id) AS "# of fishmarket visits" 
FROM users t1 
LEFT OUTER JOIN grocery t2 ON (t2.user_id=t1."id") 
LEFT OUTER JOIN fishmarket t3 ON (t3.user_id=t1."id") 
GROUP BY t1.account_balance,t1.id 
ORDER BY t1.id 

यह एक गलत परिणाम का उत्पादन: जब मैं निम्न क्वेरी कोशिश "1", "12", "12"
लेकिन जब मैं LEFT JOIN को केवल एक तालिका में करने का प्रयास करता हूं तो यह grocery या fishmarket विज़िट के लिए सही परिणाम उत्पन्न करता है, जो "1", "3", "4" हैं।

मैं यहाँ क्या गलत कर रहा हूं?
मैं PostgreSQL 9.1 का उपयोग कर रहा हूं।

उत्तर

37

जॉइन बाएं से दाएं संसाधित होते हैं (जब तक कि ब्रांड्स अन्यथा निर्देशित न करें)। यदि आप LEFT JOIN (या केवल JOIN, समान प्रभाव) एक उपयोगकर्ता को तीन किराने का सामान आपको 3 पंक्तियां (1 x 3) प्राप्त करता है। यदि आप उसी उपयोगकर्ता के लिए 4 फिशमार्केट में शामिल होते हैं, तो आपको 12 (3 x 4) पंक्तियां, गुणा करने के परिणामस्वरूप पिछली गिनती को जोड़ने के लिए, जैसा कि आप उम्मीद कर सकते हैं।
इस प्रकार किराने का सामान और मछली पकड़ने के लिए समान रूप से यात्राओं को गुणा करना।

यह इस तरह काम करना चाहिए:

SELECT u.id 
    , u.account_balance 
    , g.grocery_visits 
    , f.fishmarket_visits 
FROM users u 
LEFT JOIN (
    SELECT user_id, count(*) AS grocery_visits 
    FROM grocery 
    GROUP BY user_id 
    ) g ON g.user_id = u.id 
LEFT JOIN (
    SELECT user_id, count(*) AS fishmarket_visits 
    FROM fishmarket 
    GROUP BY user_id 
    ) f ON f.user_id = u.id 
ORDER BY u.id; 

एक या कुछ उपयोगकर्ताओं, सहसंबद्ध सबक्वेरीlike @Vince provided ठीक कर रहे हैं के लिए एकत्रित मूल्यों को देखने के लिए। पूरी तालिका या इसके प्रमुख हिस्सों के लिए, यह एन-टेबल को एकत्र करने के लिए (अधिक) अधिक कुशल है और परिणाम पर परिणाम में शामिल हो गया है। इस तरह, हमें बाहरी क्वेरी में GROUP BY की आवश्यकता नहीं है।

+2

वास्तव में इस सवाल का जवाब सिर्फ एक समाधान देने नहीं करने पर बधाई। – xception

+0

इस [लिंक] में कार्य कोड (http://rextester.com/ZFFE32806)। – HeyJude

+0

@ErwinBrandstetter मैंने आपकी पोस्ट से पोस्टग्रेस के बारे में बहुत कुछ सीखा है। क्या आपने कभी इस विषय पर एक पुस्तक लिखने पर विचार किया है? –

2

ऐसा इसलिए है क्योंकि जब उपयोगकर्ता तालिका किराने की मेज में शामिल होती है, तो 3 रिकॉर्ड मिलान होते हैं। फिर उन तीनों में से प्रत्येक रिकॉर्ड फिशमार्केट में 4 रिकॉर्ड के साथ मेल खाता है, जिसमें 12 रिकॉर्ड होते हैं। आप जो खोज रहे हैं उसे प्राप्त करने के लिए आपको सबक्वायरीज़ की आवश्यकता है।

7

अपनी मूल क्वेरी के लिए, यदि आप समूह को पूर्व-समूहित परिणाम देखने के लिए दूर ले जाते हैं, तो आप देखेंगे कि आपके द्वारा प्राप्त की जाने वाली गणना क्यों बनाई गई थी।

शायद निम्न क्वेरी सबक्वेरी उपयोग अपने इच्छित परिणाम प्राप्त होगा:

SELECT 
t1."id" AS "User ID", 
t1.account_balance AS "Account Balance", 
(SELECT count(*) FROM grocery  t2 ON (t2.user_id=t1."id")) AS "# of grocery visits", 
(SELECT count(*) FROM fishmarket t3 ON (t3.user_id=t1."id")) AS "# of fishmarket visits" 
FROM users t1 
ORDER BY t1.id 
संबंधित मुद्दे