SQL में WHERE और HAVING: पंक्तियों और समूहों को सही फ़िल्टर करें
WHERE, GROUP BY से पहले अलग-अलग पंक्तियों को फ़िल्टर करता है। HAVING, गणना के बाद समूहों को फ़िल्टर करता है। जब रिपोर्ट में पंक्ति की शर्त और कुल की शर्त दोनों हों, तब दोनों clauses इस्तेमाल करें।
“कम से कम 150 की paid बिक्री वाले क्षेत्र” में दो नियम हैं: कुल में केवल paid लेनदेन शामिल हों और सिर्फ वे क्षेत्र दिखें जिनका कुल 150 तक पहुँचे। दोनों शर्तों को एक ही जगह रखने से अर्थ बदल सकता है या क्वेरी अमान्य हो सकती है।
| शर्त | Clause |
|---|---|
| paid लेनदेन रखें | WHERE status = ‘paid’ |
| कम से कम 150 कुल वाले समूह रखें | HAVING SUM(amount) >= 150 |
| अंतिम समूहों को क्रम में रखें | ORDER BY |
समझने के लिए क्रम है: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY। यह तर्क समझने का तरीका है; डेटाबेस वास्तव में इसी क्रम में सभी काम करेगा, इसकी गारंटी नहीं।
SQLite में खुद चलाकर देखें
SQL Lab खोलें, यह सेटअप पेस्ट करें और एक बार चलाएँ। फिर हर क्वेरी अलग चलाएँ। टेबल और कॉलम के नाम अंग्रेज़ी में रखे गए हैं ताकि हर भाषा में वही SQL चले। लैब और लिंक किए गए पाठ के निर्देश अभी अंग्रेज़ी में हैं।
CREATE TABLE blog_sales (
id INTEGER PRIMARY KEY, region TEXT, status TEXT, amount INTEGER
);
INSERT INTO blog_sales VALUES
(1, 'North', 'paid', 100), (2, 'North', 'paid', 80),
(3, 'North', 'refunded', 500), (4, 'South', 'paid', 70),
(5, 'South', 'paid', 90), (6, 'West', 'paid', 40);
1. पंक्ति और समूह की शर्त साथ लगाएँ
North की paid बिक्री 180 है, 680 नहीं: refunded लेनदेन कुल में नहीं जाना चाहिए। South का कुल 160 और West का 40 है। WHERE refunded पंक्ति को GROUP BY से पहले हटाता है; HAVING फिर West को हटाता है।
SELECT region, SUM(amount) AS paid_total, COUNT(*) AS paid_orders
FROM blog_sales
WHERE status = 'paid'
GROUP BY region
HAVING SUM(amount) >= 150
ORDER BY region;
अपेक्षित नतीजा
| region | paid_total | paid_orders |
|---|---|---|
| North | 180 | 2 |
| South | 160 | 2 |
2. पंक्ति की सीमा लेनदेन हटा देती है
WHERE में amount >= 80 लगाने से South का 70 वाला paid लेनदेन हट जाता है। उसका कुल अब 90 है। यह बड़े व्यक्तिगत लेनदेन का कुल माँगता है, बड़े कुल वाले क्षेत्र नहीं।
SELECT region, SUM(amount) AS total
FROM blog_sales
WHERE status = 'paid' AND amount >= 80
GROUP BY region
ORDER BY region;
अपेक्षित नतीजा
| region | total |
|---|---|
| North | 180 |
| South | 90 |
3. समूह की सीमा योगदान देने वाली पंक्तियाँ रखती है
amount की शर्त HAVING में रखने पर South के दोनों paid लेनदेन जुड़ते हैं और कुल 160 रहता है। West हट जाता है क्योंकि उसके समूह का कुल 80 से कम है। देखने में समान शर्तें अलग व्यावसायिक उत्तर दे सकती हैं।
SELECT region, SUM(amount) AS total
FROM blog_sales
WHERE status = 'paid'
GROUP BY region
HAVING SUM(amount) >= 80
ORDER BY region;
अपेक्षित नतीजा
| region | total |
|---|---|
| North | 180 |
| South | 160 |
अभ्यास और उत्तर की जाँच
कम से कम दो paid लेनदेन वाले क्षेत्र निकालें। WHERE status = 'paid' रखें, region पर GROUP BY करें और HAVING COUNT(*) >= 2 लगाएँ। उत्तर North और South हैं, दोनों में दो लेनदेन हैं।
गलती खोजने का उपयोगी तरीका है: पहले WHERE के बाद बची पंक्तियाँ देखें, फिर HAVING के बिना कुल निकालें और अंत में समूह का फ़िल्टर जोड़ें। इससे पता चलेगा कि डेटा पंक्ति की शर्त से गायब हुआ या कुल की सीमा से।
इस grouped क्वेरी में SUM(amount) को WHERE में न रखें; उस चरण पर समूह का कुल उपलब्ध नहीं है। SELECT में id जैसा कॉलम भी न लें जब वह GROUP BY या aggregate में न हो। सख्त डेटाबेस इसे अस्वीकार करते हैं, जबकि दूसरे ऐसा मान दे सकते हैं जो पूरे समूह को नहीं दर्शाता।
अलग डेटाबेस में चलने वाली SQL के लिए HAVING में SELECT alias की जगह aggregate expression लिखें। हर WHERE को HAVING से न बदलें। हर इनपुट पंक्ति की शर्त सामान्यतः WHERE में होनी चाहिए, जब तक समूह का अर्थ जानबूझकर बदलना न हो।
दस्तावेज़ और आगे की पढ़ाई
GROUP BY और HAVING का पाठ पढ़ें। उदाहरण SQLite पर चलते हैं। पंक्ति और समूह का अंतर सामान्य relational डेटाबेस में लागू होता है, लेकिन alias और GROUP BY के नियम अलग हो सकते हैं।
SQL Lab में उदाहरण चलाएँ
इस गाइड का सेटअप और क्वेरी लैब में कॉपी करें। उदाहरण SQLite पर चलते हैं। पाठ और लैब के निर्देश अभी अंग्रेज़ी में हैं।
SQL Lab खोलें