डेटाबेस फ़ंडामेंटल्स

Database data का व्यवस्थित और स्थायी (persistent) संग्रह है: उसे लिखने वाला program बंद होने के बाद भी data बचा रहता है, इसीलिए shopping app दोबारा खोलने पर आपके orders वहीं मिलते हैं। जो software data store करता है, उसके rules लागू करता है और queries का जवाब देता है, वह database management system (DBMS) है, जैसे PostgreSQL, MySQL, SQL Server या SQLite; अक्सर दोनों को "database" ही कहा जाता है।

Relational database में data tables में रहता है: हर table एक तरह की चीज़ रखती है, हर row एक record है और हर column एक attribute है जिसका data type घोषित होता है। जब आप किसी online shop में sign up करते हैं, तो application customers table में एक row जोड़ता है — customer 317, Sara Ahmed, phone 0550000001 — और बाद में आपकी profile दिखाने वाली हर screen वही row पढ़ती है।

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

Screen वह दिखाती है जो application ने दिखाना चुना; database में वह है जो सच में stored हुआ। कई defects सिर्फ़ वहीं रहते हैं: phone number जिसका शुरुआती zero गायब हो गया, Arabic नाम जो question marks बनकर save हुआ, description जो 50 characters पर कट गया, timestamp जो तीन घंटे खिसक गया। ये defects हफ़्तों बाद किसी invoice, report या दूसरे system में सामने आते हैं।

Table कैसे बनी है, यह जानना अंदाज़े को test design में बदल देता है। हर column का type और length ऐसी limits हैं जिनका requirement में शायद ही ज़िक्र होता है, और हर optional column यह सवाल उठाता है कि "खाली" का मतलब क्या है।

Tables, rows और columns

नीचे की customers table तीन rows और अपने पाँच columns दिखाती है: हर customer के लिए एक row, हर attribute के लिए एक column, और जहाँ row और column मिलते हैं वहाँ एक अकेली value।

दो बातें beginners को चौंकाती हैं। Column का मतलब हर row में एक ही होता है: phone एक row में phone number और दूसरी में email address नहीं रख सकता। और rows का कोई built-in क्रम नहीं होता: ORDER BY के बिना database rows किसी भी क्रम में लौटा सकता है, इसलिए "आख़िरी row" अभी बनाया गया record ढूँढने का तरीका नहीं है। उसे उसके identifier से ढूँढें — यहाँ customer_id, जो एक key है और keys and relationships वाले lesson का विषय है।

customers table: हर row एक customer है, हर column एक attribute जिसका एक data type है, और birth_date में NULL का मतलब है कि कोई value stored नहीं हुई, जबकि 0.00 balance एक value है।
customer_id · INTEGERColumns: हर column एक attribute, अपने data type के साथ
full_nameVARCHAR(100)phoneVARCHAR(20)birth_dateDATEwallet_balanceNUMERIC(10,2)
317Sara Ahmed0550000001text: शुरुआती 0 बना रहता है1994-03-18250.00
318Ravi Kumar+919800000002text: + बना रहता हैNULLकोई value stored नहीं0.00zero भी एक value है
319Lina Haddad07900000032001-11-021250.50
  • Rowएक customer, हर column में एक value या NULL
  • NULL: कोई value नहीं, जो न 0 है न खाली text

काल्पनिक rows। Rows का कोई built-in क्रम नहीं होता, और worked example की definition के दो columns यहाँ छोड़े गए हैं।

  • दूसरे नाम: relational theory में table को relation कहते हैं, row को record या tuple, और column को field या attribute।
  • Schema: सभी tables, columns, types और rules की definition (PostgreSQL और SQL Server में यह tables को group करने वाला namespace भी है)।
पाठ संस्करण
Table: customers

customer_id | full_name   | phone         | birth_date | wallet_balance
------------+-------------+---------------+------------+---------------
        317 | Sara Ahmed  | 0550000001    | 1994-03-18 |         250.00
        318 | Ravi Kumar  | +919800000002 | NULL       |           0.00
        319 | Lina Haddad | 0790000003    | 2001-11-02 |        1250.50

Data types: column क्या रख सकता है

हर column एक data type घोषित करता है, जो तय करता है कि वह कौन-सी values स्वीकार करेगा, उनकी sorting और तुलना कैसे होगी, और वे कितनी बड़ी हो सकती हैं। नाम और सख़्ती engines के बीच अलग होते हैं: SQL Server BOOLEAN की जगह BIT इस्तेमाल करता है; PostgreSQL column से लंबा text या बड़ा number reject करता है, पर ज़्यादा decimal places को बिना किसी error के round कर देता है, MySQL का व्यवहार उसके SQL mode पर निर्भर करता है, और SQLite default रूप से लगभग कोई भी value किसी भी column में store कर लेता है।

  • Whole numbers — INTEGER, BIGINT: counts, quantities और identifiers। हर एक की range तय है; 4-byte INTEGER 2147483647 पर रुक जाता है।
  • Exact decimals — NUMERIC(p,s) या DECIMAL(p,s): पैसों के लिए। NUMERIC(10,2) में कुल 10 digits होते हैं, जिनमें 2 point के बाद: यह अधिकतम 99999999.99 तक जाता है, और PostgreSQL 0.125 को 0.13 के रूप में store करता है।
  • Approximate numbers — REAL, DOUBLE PRECISION: measurements के लिए, पैसों के लिए कभी नहीं: binary floating point में 0.1 + 0.2 ठीक 0.3 नहीं होता।
  • Text — VARCHAR(n), TEXT: n maximum length है। ज़्यादातर engines characters गिनते हैं, पर कुछ types bytes गिनते हैं, और UTF-8 में एक Arabic letter 2 bytes और एक Devanagari letter 3 bytes लेता है।
  • Date और time — DATE, TIMESTAMP: एक दिन या एक पल। जाँचें कि timestamp अपना time zone रखता है या नहीं: रियाद (UTC+3) में रात 01:30 बजे UTC में अभी पिछला दिन होता है।
  • Boolean — BOOLEAN: true या false; MySQL इसे छोटे integer के रूप में store करता है, इसलिए आपको 1 और 0 दिखते हैं।
  • NULL — यह type नहीं, किसी भी column में "कोई value नहीं" का marker है। यह 0 से, खाली text '' से और user के टाइप किए शब्द "NULL" से अलग है। NOT NULL column ज़रूरी (required) होता है।

आज़माएँ: CSV से SQL आज़माएँ: बाउंड्री नंबर डेटासेट जनरेटर आज़माएँ: स्ट्रिंग लेंथ काउंटर

Worked example: table definition से test ideas

एक नए profile page पर customers नाम, mobile number और optional birth date भरते हैं और अपना wallet balance देखते हैं। कोई screen बनने से पहले ही developer की नीचे दी गई table definition को test basis (वह सब कुछ जिससे आप tests निकालते हैं) के हिस्से के रूप में पढ़ें और उसके columns को test conditions (टेस्ट करने लायक पहलू) या सवालों में बदलें:

  • full_name VARCHAR(100): English, Arabic और Hindi में ठीक 100 और 101 characters (limit और उससे एक ज़्यादा) के नाम save करें। Expected: 100 वाला बिना बदलाव stored हो और 101 वाला साफ़ message के साथ reject हो, चुपचाप कटे नहीं।
  • phone VARCHAR(20): text सही type है; number type 0550000001 का शुरुआती 0 और +919800000002 का + गिरा देगा। Stored value को character-दर-character मिलाएँ।
  • birth_date DATE NULL: field खाली छोड़ें। Expected: row में NULL हो, 1900-01-01 जैसी placeholder date नहीं।
  • wallet_balance NUMERIC(10,2): 0.10 तीन बार top up करें और ठीक 0.30 की उम्मीद रखें। पूछें कि जब top-up से balance column की maximum value 99999999.99 से ऊपर जाए तो क्या होगा।
  • created_at TIMESTAMP: PostgreSQL में यह type time zone नहीं रखता। रियाद के समय से रात 01:30 बजे sign up करें और पूछें कि stored value UTC है या local time; हर daily report इसी जवाब पर निर्भर है।
CREATE TABLE customers (
  customer_id     INTEGER        NOT NULL,
  full_name       VARCHAR(100)   NOT NULL,
  phone           VARCHAR(20)    NOT NULL,
  birth_date      DATE           NULL,
  wallet_balance  NUMERIC(10,2)  NOT NULL DEFAULT 0,
  is_active       BOOLEAN        NOT NULL DEFAULT TRUE,
  created_at      TIMESTAMP      NOT NULL,
  CONSTRAINT pk_customers PRIMARY KEY (customer_id)
);

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

Relational और दूसरे तरह के databases

SQL से query होने वाले relational databases business records के लिए बड़े पैमाने पर इस्तेमाल होते हैं, और यही इस module का फ़ोकस हैं। SQL को ISO/IEC 9075 में standardise किया गया है, पर हर engine अपनी dialect जोड़ता है। Non-relational ("NoSQL") databases data को अलग तरह से व्यवस्थित करते हैं और अक्सर checks application पर छोड़ देते हैं:

  • Document databases, जैसे MongoDB, JSON जैसे documents store करते हैं, जिनके fields एक ही collection में अलग-अलग हो सकते हैं जब तक कोई validation rule मना न करे; missing या गलत spelling वाले fields और text के रूप में stored numbers टेस्ट करें।
  • Key-value stores, जैसे Redis, एक key के नीचे एक value रखते हैं, अक्सर ऐसे cache के रूप में जो अपने पीछे वाले database से पुराना पड़ सकता है।
  • Wide-column stores, जैसे Apache Cassandra, बहुत बड़ी tables को कई servers पर फैलाते हैं।
  • Graph databases, जैसे Neo4j, nodes और उनके बीच के relationships store करते हैं, जैसे कौन किसे follow करता है।

आज़माएँ: JSON से SQL

आम गलतियाँ

  • Screen को इस बात का सबूत मान लेना कि क्या stored हुआ; page वही दोहरा सकता है जो आपने टाइप किया, जबकि row में कटी या बिगड़ी value हो।
  • नया record उसकी key से ढूँढने की बजाय "आख़िरी row" उठाकर ढूँढना।
  • Test data और expected results में NULL, 0 और खाली text को एक ही चीज़ मानना।
  • Digits से बनी हर चीज़ के लिए number type स्वीकार कर लेना: phone numbers, barcodes और national ids text हैं, क्योंकि शुरुआती zeros और formatting मायने रखते हैं।
  • Shared test database पर data "ठीक" करने के लिए उसके owner की सहमति के बिना UPDATE या DELETE चलाना।

QA का नज़रिया

Backlog refinement या design review में नए feature की table definition माँगें और उसे test basis के हिस्से के रूप में पढ़ें। हर column वही सवाल उठाता है — required या optional, कौन-सा type, कितनी length या range, कौन-सा time zone, क्या default — और कोई mismatch, जैसे 100 characters वाले column के लिए 150 characters स्वीकार करने वाला form, coding से पहले उठाना सबसे अच्छा है।

Testing के दौरान test database का read-only access माँगें और पुष्टि करें कि हर action ने क्या store किया। Bug report में table, column, row की key, expected value और actual value लिखें: "customer_id 318 के लिए customers.phone में 919800000002 है, expected +919800000002"।

अभ्यास

Product table के लिए data types चुनें

आपका काम

एक shop नीचे दी गई product list को नई products table में import करना चाहती है। Barcode 13 digits का EAN-13 code है जो 0 से शुरू हो सकता है। Table design करें, फिर हर column के लिए एक test idea लिखें।

बाद में अपने choices की तुलना उन types से करें जो CSV to SQL tool sample से infer करता है: वह values से लगाया गया अंदाज़ा है, मतलब पर लिया गया फ़ैसला नहीं।

सामग्री
sku,name_en,name_ar,price_sar,stock_qty,weight_kg,launch_date,online,barcode
TEA-001,Green tea,شاي أخضر,18.50,240,0.125,2026-03-01,yes,0614141000012
CUP-014,Glass cup,كوب زجاجي,9.95,0,0.250,2025-11-20,no,0614141000029
चरण
  1. हर column को classify करें: हिसाब लगाने वाला number, digits से बना code, text, date या yes/no।
  2. हर column के लिए type चुनें, जहाँ ज़रूरी हो वहाँ length या precision के साथ, और उसे required या optional चिह्नित करें।
  3. वह column चुनें जो row पहचानता है, फिर हर column के लिए expected result के साथ एक test idea लिखें।
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

PostgreSQL types में एक उचित design: sku VARCHAR(20) NOT NULL (row पहचानता है), name_en VARCHAR(200) NOT NULL, name_ar VARCHAR(200) NOT NULL, price_sar NUMERIC(10,2) NOT NULL, stock_qty INTEGER NOT NULL, weight_kg NUMERIC(8,3) NULL, launch_date DATE NULL, is_online BOOLEAN NOT NULL (online column, yes/no की तरह पढ़ने के लिए नया नाम), barcode VARCHAR(13) NULL।

जाल: barcode number नहीं, code है — BIGINT में 0614141000012 अपना शुरुआती zero खो देगा, इसलिए उसे text होना चाहिए। Price पैसा है, इसलिए exact decimal चाहिए, REAL कभी नहीं। Yes/no column BOOLEAN बनता है, और import को तय करना होगा कि "Yes" या "Y" का क्या मतलब है।

Test ideas: duplicate SKU reject हो; 200 characters के नाम बिना बदलाव stored हों; 18.50 ठीक 18.50 ही रहे; 0 stock 0 के रूप में stored हो, खाली stock reject हो; 0.125 weight तीन decimals रखे; खाली launch date NULL बने; "no" false बने; barcode अपना शुरुआती zero रखे, और 12 digits का barcode reject हो — अकेला VARCHAR(13) उसे स्वीकार कर लेगा, इसलिए पूछें कि database का कोई check या import ठीक 13 digits लागू करता है या नहीं।

CSV to SQL tool अपने types सिर्फ़ इन दो rows से तय करता है: price के लिए DECIMAL(4,2) सुझाता है, जो 99.99 पर रुक जाता है, और दोनों names के लिए VARCHAR(20), जो असली product names के लिए छोटा है। शुरुआती zero की वजह से वह barcode को text ही रखता है। Inferred types को review करने लायक पहला draft मानें, design नहीं।

Product owner के लिए सवाल: क्या weight से shipping fee निकलती है? क्या दो products का एक ही barcode हो सकता है? असली product name कितना लंबा हो सकता है?

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

क्या database टेस्ट करने के लिए SQL ज़रूरी है?

हाँ, basic level पर। WHERE condition वाली एक SELECT query ज़्यादातर verification सवालों का जवाब दे देती है, और इस module के आगे के lessons इसे सिखाते हैं। Database design करना ज़रूरी नहीं, पर table definition पढ़ना और अपने test से बनी rows को query करना आना चाहिए।

Database और table में क्या फ़र्क है?

Database पूरा संग्रह है: आम तौर पर कई tables, साथ में उनके आसपास के rules, users और permissions। Table उसके अंदर की एक structure है जो एक तरह के records रखती है, जैसे customers या orders।

क्या NoSQL relational database से बेहतर है?

सामान्य तौर पर दोनों में से कोई भी बेहतर नहीं है। दोनों structure, querying और scaling में अलग trade-offs करते हैं, और कई products दोनों इस्तेमाल करते हैं। Tester के रूप में पता करें कि कौन-सा store कौन-सा data रखता है, हर store कौन-से rules ख़ुद लागू करता है और कौन-से application पर छोड़ता है।

संदर्भ

  • 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 से अभ्यास करें

CSV डेटा को अनुमानित कॉलम टाइप के साथ CREATE TABLE और INSERT स्टेटमेंट में बदलें।

डेटाबेस

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

टेस्ट डेटा

कई लिपियों (अरबी, देवनागरी, CJK, सिरिलिक), emoji, संयोजक चिह्न और normalisation रूपों में Unicode टेस्ट स्ट्रिंग जनरेट करें।

टेस्ट डेटा

ऑब्जेक्ट के JSON ऐरे को SQL INSERT स्टेटमेंट में बदलें (चाहें तो CREATE TABLE के साथ)।

डेटाबेस

और गहराई से

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

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