5

मेरे पास टेबल बी & सी तालिका कुंजी के माध्यम से तालिका ए के साथ 3 टेबल हैं। मैं PostgreSQL में एक प्रश्न लिखने के लिए बी & से एक से और साथ ही उनका कुल घटनाओं सभी आईडी प्राप्त करने के लिए सी चाहतेएकाधिक तालिकाओं से विदेशी कुंजी की गिनती प्राप्त करें

a  |  b  |  c 
-----------------------------------  
id | txt | id | a_id | id | a_id 
---+---- | ---+----- | ---+------ 
1 | a | 1 | 1 | 1 | 3  
2 | b | 2 | 1 | 2 | 4  
3 | c | 3 | 3 | 3 | 4  
4 | d | 4 | 4 | 4 | 4  

आउटपुट (बी & सी में एक & कुल संख्या से सिर्फ आईडी) वांछित:

id | Count 
---+------- 
1 | 2  -- twice in B 
2 | 0  -- occurs nowhere 
3 | 2  -- once in B & once in C 
4 | 4  -- once in B & thrice in C 

एसक्यूएल अब तक SQL Fiddle:

SELECT a_id, COUNT(a_id) 
FROM 
(SELECT a_id FROM b 
    UNION ALL 
    SELECT a_id FROM c 
) AS union_table 
GROUP BY a_id 

क्वेरी मैंने लिखा बीसे हासिल करेगासी और घटनाओं की गणना करता है। लेकिन यदि कुंजी बी या सी में नहीं होती है, तो यह आउटपुट में दिखाई नहीं देती है (उदाहरण के लिए आउटपुट में आईडी = 2)। मैं मेज से मेरा चयन कैसे शुरू कर सकते हैं एक & में शामिल होने/संघ बी & सी वांछित आउटपुट

उत्तर

4

हैं क्वेरी में b और/या c के बड़े हिस्से शामिल हैं, यह पहले एकत्र करने और बाद में शामिल होने के लिए अधिक कुशल है।
मैं इन दो वेरिएंट काफी तेज होने की उम्मीद:

SELECT a.id, 
     ,COALESCE(b.ct, 0) + COALESCE(c.ct, 0) AS bc_ct 
FROM a 
LEFT JOIN (SELECT a_id, count(*) AS ct FROM b GROUP BY 1) b USING (a_id) 
LEFT JOIN (SELECT a_id, count(*) AS ct FROM c GROUP BY 1) c USING (a_id); 

आप संभावना है कि कुछ a_ida और/या b में बिल्कुल भी मौजूद नहीं हैं के लिए खाते में करने की जरूरत है। count()NULL कभी नहीं लौटाता है, लेकिन LEFT JOIN के चेहरे में यह ठंडा आराम है, जो आपको गायब पंक्तियों के लिए NULL मानों के साथ छोड़ देता है। आप NULL के लिए तैयार होना चाहिए। COALESCE() का उपयोग करें।

या, दोनों तालिकाओं, कुल से यूनिअन सभी a_idतो शामिल हों:

SELECT a.id 
     ,COALESCE(ct.bc_ct, 0) AS bc_ct 
FROM a 
LEFT JOIN (
    SELECT a_id, count(*) AS bc_ct 
    FROM (
     SELECT a_id FROM b 
     UNION ALL 
     SELECT a_id FROM c 
    ) bc 
    GROUP BY 1 
    ) ct USING (a_id); 

शायद धीमी। लेकिन अभी तक प्रस्तुत समाधानों की तुलना में तेज़ है। और आप COALESCE() के बिना कर सकते हैं और अभी भी किसी भी पंक्ति को ढीला नहीं कर सकते हैं। इस मामले में आपको bc_ct के लिए कभी-कभी NULL मान मिल सकते हैं।

+0

आप क्यों कहते हैं कि आपका दूसरा विकल्प शायद धीमा है? इसमें कम जॉइन हैं, क्या यह तेज़ नहीं होना चाहिए? – click

+0

@click मैं PostgreSQL (इससे दूर) के साथ एक विशेषज्ञ नहीं हूं, लेकिन शायद 'ग्रुप बाय' जैसे कुल फ़ंक्शन का उपयोग करना धीमा हो जाएगा। लेकिन इसके बारे में बेहतर सोचते हुए, मुझे वास्तव में यह नहीं पता कि इरविन की पहली क्वेरी मेरे उत्तर से तेज क्यों होनी चाहिए (मेरा मानना ​​है कि दोनों ओरेकल और एसक्यूएल सर्वर जैसे डेटाबेस में समान निष्पादन योजनाएं होंगी), लेकिन मुझे लगता है * वह जानता है कि वह क्या जानता है के बारे में बात कर रहा है – rsenna

+0

@click: जुड़ने की संख्या कई कारकों में से एक है। यह सब कार्डिनिटीज और डेटा वितरण (दूसरों के बीच) पर निर्भर करता है। यही कारण है कि मैं ठेठ मामलों और संभावनाओं के बारे में बात करता हूं। निश्चित रूप से जानने के लिए आपको अपने * वास्तविक * परिदृश्य से परीक्षण करना होगा। पहली क्वेरी आमतौर पर सादगी और प्रभावशीलता के बीच एक मीठा स्थान हिट करती है। –

2

उपयोग छोड़ दिया एक सबक्वेरी के साथ शामिल हो पाने के लिए:

SELECT a.id, COUNT(x.id) 
FROM a 
LEFT JOIN (
    SELECT id, a_id FROM b 
    UNION ALL 
    SELECT id, a_id FROM c 
) x ON (a.id = x.a_id) 
GROUP BY a.id; 
+0

इच्छा है कि मैं दोनों उत्तरों को स्वीकार कर सकूं। जब मेरे पास अधिक डेटा होता है, तो मैं यह देखने के लिए आऊंगा कि यह बेहतर प्रदर्शन करता है लेकिन ऐसा लगता है कि दूसरा जॉइन से बचाता है और तेज़ी से हो सकता है। – click

+0

यहां तक ​​कि एक तीसरा संभावित समाधान भी है। – wildplasser

3

एक अन्य विकल्प:

SELECT 
    a.id, 
    (SELECT COUNT(*) FROM b WHERE b.a_id = a.id) + 
    (SELECT COUNT(*) FROM c WHERE c.a_id = a.id) 
FROM 
    a 
+0

यह साफ है। मुझे नहीं पता था कि आप चयन के अंदर चयन कथन चुन सकते हैं और उन्हें आसानी से जोड़ सकते हैं। – click

+3

@click: 'a_id' मानों के मुट्ठी भर से अधिक के लिए, ** [सहसंबंधित सबक्वायरीज़] (http://en.wikipedia.org/wiki/Correlated_subquery) ** (वह शब्द है) आम तौर पर वैकल्पिक से धीमे * होते हैं समाधान की। Postgres प्रति 'a_id' मान एक subquery चलाने की जरूरत है। डेटा के यथार्थवादी सेट के साथ परीक्षण करना सुनिश्चित करें। –

+0

प्रदर्शन के लिए @ErwinBrandstetter से स्वीकृत उत्तर को बदल दिया। लेकिन छोटी टेबल के लिए, यह कॉम्पैक्टनेस के लिए जीतता है। तुलना करने के लिए मेरे पास अधिक डेटा होने पर मैं इसे फिर से देखूंगा। – click

संबंधित मुद्दे