SQL बेसिक्स: SELECT, WHERE और ORDER BY

SQL (Structured Query Language) relational databases से query करने की standard language है। SELECT statement कुछ भी बदले बिना rows पढ़ता है: यह CRUD का read है। FROM बताता है कि किस table से पढ़ना है, और ज़्यादातर काम तीन clauses करते हैं: SELECT columns बताता है, WHERE condition से match होने वाली rows रखता है और ORDER BY result को sort करता है।

उदाहरण के लिए, SELECT order_id, status FROM orders WHERE customer_id = 207 ORDER BY created_at DESC; customer 207 के orders सबसे नए पहले दिखाता है। Testers ऐसी queries से देखते हैं कि application ने असल में क्या store किया, और expected results निकालते हैं।

यह क्यों ज़रूरी है

Screen और API data तब दिखाते हैं जब application उसे filter और format कर चुका होता है; database दिखाता है कि असल में क्या store हुआ। जब कोई test fail हो, या गलत वजह से pass हो, तो एक छोटी query बता देती है कि defect data में है या उसे दिखाने वाले code में, और developer को दोबारा चलाने लायक evidence देती है।

SELECT वह जगह भी है जहाँ beginners चुपचाप गलतियाँ करते हैं: = NULL लिखी condition, छूटे हुए parentheses या ORDER BY के बिना पढ़ी गई list कोई error नहीं देती। वह गलत rows लौटाती है, और उन पर भरोसा करने वाला tester टूटे feature को pass कर देता है या ऐसा bug report करता है जो है ही नहीं।

SELECT statement कैसे बनता है

SQL declarative है: आप result बताते हैं और database तय करता है कि उसे कैसे बनाना है। Language को standard ISO/IEC 9075 परिभाषित करता है; PostgreSQL, MySQL, SQLite या SQL Server जैसा हर engine इसकी एक dialect implement करता है, और यहाँ की basics सबमें चलती हैं, जब तक कोई note कुछ और न कहे।

Statement clauses से बनता है जो keywords से शुरू होते हैं। Keywords पर case का असर नहीं पड़ता, पर capitals से query पढ़ना आसान होता है। Text single quotes में जाता है ('PAID'); standard SQL और PostgreSQL में double quotes का मतलब column या table का नाम है। -- से comment शुरू होता है और ; statement ख़त्म करता है। Result खुद एक table है, और zero rows एक valid जवाब है, error नहीं।

Clauses logically उस क्रम से अलग क्रम में evaluate होते हैं जिसमें वे लिखे जाते हैं: FROM, WHERE, SELECT list, ORDER BY, फिर LIMIT। इसलिए SELECT list में AS से बना alias ORDER BY में चलता है पर WHERE में नहीं, जो alias बनने से पहले चलता है। PostgreSQL और MySQL वहाँ इसे reject करते हैं; SQLite इसे स्वीकार करता है, इसलिए SQLite पर practice में चलने वाली query project के engine पर fail हो सकती है।

SELECT को SELECT, FROM, WHERE, ORDER BY, LIMIT क्रम में लिखा जाता है, पर logically FROM, WHERE, SELECT, ORDER BY, LIMIT क्रम में evaluate किया जाता है; इस query के clauses के नंबर उसी logical क्रम में हैं।

Customer 207 के paid orders, सबसे नए पहले

-- Paid orders of customer 207, newest first
भाग 3:SELECT order_id, total_amount AS total, created_at
भाग 1:FROM orders
भाग 2:WHERE customer_id = 207
  AND status = 'PAID'
भाग 4:ORDER BY created_at DESC, order_id DESC
भाग 5:LIMIT 5;
  • 1–2कौन-सी rows
  • 3कौन-से columns
  • 4–5किस क्रम में, और कितनी
  1. 1FROM: tableसबसे पहले evaluate होता है: वह table बताता है जिसकी rows पर बाद के सभी clauses काम करते हैं।लिखने में दूसरा
  2. 2WHERE: rowsसिर्फ़ वे rows रखता है जिनके लिए पूरी condition true हो; जहाँ वह false हो या NULL के कारण unknown, वे rows हट जाती हैं।लिखने में तीसरा
  3. 3SELECT list: columnsColumns और उनके नाम चुनता है। Alias total यहीं से मौजूद है, इसलिए ORDER BY इसे इस्तेमाल कर सकता है; standard SQL इसे WHERE में इस्तेमाल करने नहीं देती।लिखने में पहला
  4. 4ORDER BY: क्रमसबसे नया पहले; order_id DESC एक ही पल में बने orders के बीच tie तोड़ता है। इस clause के बिना क्रम तय नहीं होता।लिखने में चौथा
  5. 5LIMIT: कितनी rowsSorted result की पहली 5 rows रखता है। SQL Server TOP (5) लिखता है; standard रूप FETCH FIRST 5 ROWS ONLY है।लिखने में पाँचवाँ

नंबर वह logical क्रम दिखाते हैं जो result तय करता है, वह क्रम नहीं जिसमें engine असल में data पढ़ता है।

पाठ संस्करण
-- Paid orders of customer 207, newest first
SELECT order_id, total_amount AS total, created_at
FROM orders
WHERE customer_id = 207
  AND status = 'PAID'
ORDER BY created_at DESC, order_id DESC
LIMIT 5;

आज़माएँ: SQL फ़ॉर्मेटर आज़माएँ: SQL क्वेरी वैलिडेटर

SELECT से columns और WHERE से rows चुनना

जिन columns को check करते हैं उनके नाम लिखें, जैसे SELECT order_id, status, और SELECT * सिर्फ़ जल्दी नज़र डालने के लिए रखें, ताकि saved checks bug report में पढ़ने लायक रहें। AS output column का नाम बदलता है, और SELECT DISTINCT status FROM orders हर value एक बार दिखाता है: ऐसी values पकड़ने का तेज़ तरीका जिनकी किसी ने उम्मीद नहीं की थी, जैसे 'CANCELLED' के बगल में 'CANCELED'।

WHERE हर row के लिए evaluate होता है, और सिर्फ़ वे rows लौटती हैं जिनके लिए वह true हो। यह इन हिस्सों से बनता है:

  • Comparisons: =, <> (ज़्यादातर engines != भी स्वीकार करते हैं), <, <=, >, >=।
  • Logic: AND OR से पहले evaluate होता है, इसलिए status = 'PAID' OR status = 'SHIPPED' AND total_amount > 500 सारे paid orders और 500 से ऊपर के shipped orders लौटाता है। जो मतलब है उसे parentheses से साफ़ करें।
  • Lists और ranges: status IN ('PAID', 'SHIPPED'); BETWEEN 100 AND 300 में दोनों सिरे शामिल हैं। Timestamps के लिए half-open range इस्तेमाल करें, जिसमें शुरुआत शामिल हो और अंत नहीं: created_at >= '2026-09-01' AND created_at < '2026-10-01'।
  • Patterns: LIKE '%@example.com', जहाँ % characters की कोई भी sequence (खाली भी) और _ ठीक एक character match करता है। Case sensitivity engine और column के collation पर निर्भर है, यानी text को compare और sort करने के उसके नियम: PostgreSQL text को case-sensitive तरीके से compare करता है, MySQL के default collations नहीं, और SQLite में LIKE ASCII letters का case नहीं देखता जबकि = देखता है।

आज़माएँ: SQL IN क्लॉज़ जनरेटर

ORDER BY से result sort करना

ORDER BY के बिना rows का क्रम तय नहीं होता: data बढ़ने, index (वह structure जिससे database rows जल्दी ढूँढता है) जुड़ने या engine upgrade होने पर वह बदल सकता है। जो check “पहली row” पढ़ता है या किसी list की screen से तुलना करता है, उसे साफ़ तौर पर sort करना चाहिए।

ORDER BY created_at DESC, order_id DESC दूसरा column तभी इस्तेमाल करता है जब पहला बराबर हो; ASC default है। अंत में primary key जैसा unique column रखें: इस tie-breaker के बिना बराबर rows हर run में जगह बदल सकती हैं, और paging में कोई row दो pages पर या किसी पर भी नहीं दिख सकती।

  • LIMIT 10 sorting के बाद पहली दस rows रखता है। SQL Server TOP (10) लिखता है; standard रूप FETCH FIRST 10 ROWS ONLY PostgreSQL में चलता है, MySQL और SQLite में नहीं।
  • Text column के collation से sort होता है, और text के रूप में stored numbers text की तरह sort होते हैं: '10' '9' से पहले आता है। Screen पर ऐसे sort हुई price list column का data type जाँचने की वजह है।

NULL: वह value जो मौजूद नहीं

NULL किसी missing या unknown value को दर्शाता है; यह zero नहीं, खाली string '' नहीं और text 'NULL' भी नहीं। NULL से comparison न true होता है न false, बल्कि unknown, और WHERE सिर्फ़ true rows रखता है, इसलिए जिन rows में compare किया गया column NULL है, वे बिना किसी चेतावनी के results से गायब हो जाती हैं।

Unknown AND और OR से होकर भी आगे जाता है। AND तभी true होता है जब दोनों तरफ़ true हों, इसलिए true AND unknown unknown है और row हट जाती है; OR को एक true तरफ़ काफ़ी है, इसलिए unknown OR true true है और row रहती है।

  • WHERE email = NULL कभी कोई row नहीं लौटाता। IS NULL और IS NOT NULL इस्तेमाल करें।
  • WHERE city <> 'Riyadh' उन rows को भी हटा देता है जिनकी city NULL है, और NOT (city = 'Riyadh') भी। अगर वे rows result में चाहिए, तो OR city IS NULL जोड़ें।
  • NULL के साथ arithmetic का नतीजा NULL है; COALESCE(delivery_fee, 0) अपना पहला ऐसा argument लौटाता है जो NULL न हो।
  • PostgreSQL, MySQL और SQLite में खाली string NULL नहीं है (Oracle Database '' को NULL के रूप में store करता है), इसलिए required field का check दोनों को ढूँढता है।
  • Ascending order में PostgreSQL NULL को आख़िर में रखता है, MySQL और SQLite शुरू में; descending order में हर engine इसका उल्टा करता है। Position साफ़ तय करने के लिए PostgreSQL और SQLite NULLS FIRST या NULLS LAST स्वीकार करते हैं।
-- Customers without a usable email address
SELECT customer_id, full_name
FROM customers
WHERE email IS NULL OR email = '';

-- Show a default where the value is missing
SELECT order_id, COALESCE(coupon_code, 'none') AS coupon
FROM orders
WHERE customer_id = 207;

Worked example: “My orders” page की जाँच

Requirement: “My orders customer के orders दिखाता है, cancelled छोड़कर, सबसे नया पहले; एक ही समय पर बने orders order number से आते हैं, सबसे बड़ा पहले; एक page पर अधिकतम 10 orders।” Tester पहले वह query लिखता है जो test data से expected list बनाती है, ताकि test oracle, यानी expected result का source, नियम से आए, screen से नहीं।

Customer 207 के पाँच orders हैं; order 1003 किसी दूसरे customer का है। Query की हर line नियम का एक हिस्सा जाँचती है:

  • customer_id = 207: अगर order 1003 दिखे, तो एक customer दूसरे customer का data देख रहा है — यह privacy defect है।
  • status <> 'CANCELLED': order 1002 expected नहीं है। यहाँ status NOT NULL है; अगर यह NULL स्वीकार करता, तो यही condition बिना status वाले orders भी छिपा देती।
  • ORDER BY created_at DESC, order_id DESC: 1004 और 1005 का created_at एक ही है, इसलिए tie-breaker 1005 को पहले रखता है। जो page 1004 पहले दिखाए, या reload पर दोनों की जगह बदल दे, वह नियम तोड़ता है।
  • LIMIT 10: page size एक boundary है। Boundary value analysis की तरह ठीक 10 और 11 non-cancelled orders से test करें: 11वाँ order दूसरे page पर आना चाहिए, और कोई order दो बार नहीं। LIMIT 10 OFFSET 10 पहली दस rows छोड़कर expected दूसरा page देता है।
-- Test data: orders
-- order_id  customer_id  status     total_amount  created_at
-- 1001      207          PAID       120.00        2026-09-03 10:15
-- 1002      207          CANCELLED   80.00        2026-09-05 18:40
-- 1003      311          PAID       455.50        2026-09-06 09:05
-- 1004      207          SHIPPED    455.50        2026-09-12 21:30
-- 1005      207          PAID        60.00        2026-09-12 21:30
-- 1006      207          PAID        35.25        2026-09-20 08:00

SELECT order_id, status, total_amount, created_at
FROM orders
WHERE customer_id = 207
  AND status <> 'CANCELLED'
ORDER BY created_at DESC, order_id DESC
LIMIT 10;

-- Expected, top to bottom: 1006, 1005, 1004, 1001

आज़माएँ: SQL डेटासेट जनरेटर

आम गलतियाँ

  • = NULL या <> NULL लिखना: query zero rows लौटाती है, और zero rows की उम्मीद करने वाला check गलत वजह से pass हो जाता है।
  • भूल जाना कि <> और NOT उन rows को भी हटा देते हैं जहाँ column NULL है।
  • ORDER BY या tie-breaker के बिना result की screen से तुलना करना, और फिर ऐसा sorting bug report करना जो असल में undefined order है।
  • AND और OR को बिना parentheses मिलाना, जिससे filter वे rows लौटाता है जिन्हें requirement बाहर रखती है।
  • Timestamp column पर BETWEEN '2026-09-01' AND '2026-09-30' इस्तेमाल करना: इससे 30 सितंबर को 00:00 के बाद की हर row छूट जाती है।
  • बिना control के खाली result पर भरोसा करना: 'CANCELLED' की जगह 'CANCELED' जैसी गलत spelling वाली value भी zero rows लौटाती है। पहले ऐसी row query करें जिसके होने का आपको पता है।

QA का नज़रिया

Testers SELECT का इस्तेमाल tests तैयार करने (data चुनने और expected results निकालने), किसी action ने क्या store किया यह confirm करने, जैसा CRUD operations वाले lesson में देखा, और failure की जाँच में data problem को display problem से अलग करने के लिए करते हैं। यह सब पढ़ना है: test environment में read-only account इस्तेमाल करें, और सुविधा के लिए कभी production का personal data न खंगालें।

Query को test evidence मानें: statement, environment और लौटी rows को test case या bug report में रखें, ताकि developer उसे दोबारा चला सके। Developers से पूछें कि कौन-से columns NULL हो सकते हैं, और product owner से पूछें कि value missing होने पर users को क्या दिखना चाहिए; वही जवाब आपके NULL cases का expected result है।

अभ्यास

Email campaign वाली query का review

आपका काम

Marketing team Riyadh के बाहर के हर उस customer को email भेजना चाहती है जिसके पास email address है, सबसे ज़्यादा loyalty points वाले पहले। छह sample rows के आधार पर अनुमान लगाएँ कि नीचे दी गई developer की query क्या लौटाएगी, उसके defects खोजें, और result के साथ सुधरी हुई query लिखें।

कुछ defects असल में requirement के बारे में सवाल हैं: उन्हें product owner के लिए लिखें।

सामग्री
-- Test data: customers
-- customer_id  full_name     city    email               loyalty_points
-- 1            Layla Hassan  Riyadh  layla@example.com   120
-- 2            Omar Saleh    Jeddah  NULL                300
-- 3            Priya Nair    Dammam  ''                  NULL
-- 4            Khalid Ali    NULL    khalid@example.com  450
-- 5            Sara Ahmed    Jeddah  sara@example.com    75
-- 6            Rahul Mehta   Dammam  rahul@example.com   NULL

-- The developer's query
SELECT customer_id, full_name, email
FROM customers
WHERE city <> 'Riyadh' AND email <> NULL
ORDER BY loyalty_points;
चरण
  1. हर row के लिए WHERE condition का हर हिस्सा evaluate करें: true, false या unknown।
  2. Query जो rows लौटाती है, उन्हें लिखें।
  3. Defects और उनसे उठने वाले requirement के सवाल लिखें।
  4. सुधरी हुई query और उसकी rows क्रम से लिखें।
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

city <> 'Riyadh' row 1 के लिए false, rows 2, 3, 5 और 6 के लिए true, और row 4 के लिए unknown है; email <> NULL हर row के लिए unknown है।

AND तभी true होता है जब दोनों तरफ़ true हों, इसलिए कोई row qualify नहीं करती: query कोई row नहीं लौटाती, और कोई चेतावनी भी नहीं मिलती।

Defects: email <> NULL को email IS NOT NULL होना चाहिए; customer 3 की खाली string NULL नहीं है, इसलिए email = '' को भी बाहर करें; sort DESC होना चाहिए; customer 6 के NULL points engine के हिसाब से पहले या आख़िर में आते हैं; और बराबर points के लिए कोई tie-breaker नहीं है।

Product owner से सवाल: क्या बिना city वाला customer (customer 4) Riyadh के बाहर गिना जाए? क्या missing loyalty points को 0 माना जाए?

अगर दोनों जवाब हाँ हैं, तो SELECT customer_id, full_name, email FROM customers WHERE (city <> 'Riyadh' OR city IS NULL) AND email IS NOT NULL AND email <> '' ORDER BY COALESCE(loyalty_points, 0) DESC, customer_id; customers 4 (450 points), 5 (75) और 6 (कोई points नहीं) इसी क्रम में लौटाती है। अगर बिना city वाले customers बाहर रखे जाएँ, तो result 5, फिर 6 है।

अक्सर पूछे जाने वाले सवाल

क्या मुझे किसी ख़ास database की SQL सीखनी होगी?

अपने project के engine से शुरू करें। SELECT, WHERE, ORDER BY और IS NULL, PostgreSQL, MySQL, SQLite, SQL Server और Oracle Database में एक ही तरह लिखे जाते हैं; सबसे पहले मिलने वाले अंतर हैं row limits, date functions, text comparison की case sensitivity और NULLs की sort position। जब कोई query एक project से दूसरे में जाए, तो इन्हें अपने engine के documentation में जाँचें।

क्या shared database पर SELECT चलाना safe है?

SELECT data नहीं बदलता, पर उसकी भी क़ीमत है: selective WHERE के बिना बड़ी table पर query सबके लिए database धीमा कर सकती है, और rows में personal data हो सकता है। Read-only account इस्तेमाल करें, primary key या date range पर filter करें, explore करते समय LIMIT जोड़ें, और production access के लिए अपनी team के नियम मानें।

Database server के बिना practice कैसे करूँ?

SQLite पूरा database एक file में रखता है और उसे server की ज़रूरत नहीं, बस उसका command-line shell sqlite3 काफ़ी है, इसलिए practice के लिए यह आम पसंद है। Table और sample rows SQL script के रूप में generate करें, उन्हें load करें, और इस lesson की queries दोबारा चलाएँ — हर result का अनुमान पहले लगाकर। याद रखें कि कुछ जगहों पर SQLite ज़्यादातर engines जितना सख़्त नहीं है, जैसे WHERE में alias स्वीकार करना।

संदर्भ

  • ISO/IEC 9075-1:2023 — Information technology — Database languages SQL — Part 1: Framework (SQL/Framework)ISO/IEC · 2023अंतरराष्ट्रीय SQL मानक का framework भाग, जिसे PostgreSQL, MySQL, SQLite आदि की बोलियाँ अलग-अलग हद तक लागू करती हैं।
  • PostgreSQL Documentation: SQL SyntaxThe PostgreSQL Global Development GroupPostgreSQL में SQL की लेक्सिकल संरचना: आइडेंटिफ़ायर, क्वोटिंग, स्ट्रिंग कॉन्स्टेंट और एस्केपिंग।
  • SQL As Understood By SQLiteSQLiteSQLite द्वारा स्वीकृत SQL व्याकरण, स्टेटमेंट दर स्टेटमेंट, सिंटैक्स डायग्राम के साथ।

Mutqan tools से अभ्यास करें

SQL स्टेटमेंट में सिंटैक्स की समस्याएँ, असंतुलित कोष्ठक, बिना बंद की स्ट्रिंग और जोखिम भरे पैटर्न जाँचें।

डेटाबेस

SQL क्वेरी को एकसमान कीवर्ड केसिंग, इंडेंटेशन और लाइन ब्रेक के साथ फ़ॉर्मेट करें (MySQL, PostgreSQL, SQL Server, Oracle, SQLite)।

डेटाबेस

किसी भी dialect के लिए वास्तविक जैसी टेस्ट पंक्तियों के साथ SQL seed स्क्रिप्ट (CREATE TABLE + INSERT) जनरेट करें।

टेस्ट डेटा

वैल्यू की सूची (हर लाइन पर एक या कॉमा से अलग) को कोट किए SQL IN (...) क्लॉज़ में बदलें।

डेटाबेस

और गहराई से

इस topic में आपकी प्रगति

QA रोडमैप का हिस्सा