SQL में INSERT, UPDATE और DELETE
INSERT, UPDATE और DELETE वे SQL statements हैं जो data बदलते हैं; कई teams इन्हें DML (data manipulation language) कहती हैं। INSERT नई rows जोड़ता है, UPDATE मौजूदा rows के columns बदलता है और DELETE rows हटाता है। UPDATE orders SET status = 'CANCELLED' WHERE order_id = 9101 एक order बदलता है; WHERE वाली line के बिना यह table का हर order बदल देता।
Testers इन्हें test databases पर test के लिए ज़रूरी data seed करने, records को ऐसी states में लाने जहाँ product से पहुँचने में देर लगती है, और यह जाँचने के लिए इस्तेमाल करते हैं कि database अपने rules तोड़ने वाला data reject करता है। हर बदलाव उसी SELECT और WHERE से शुरू होता है जो आप जानते हैं।
यह क्यों ज़रूरी है
गलत SELECT गलत जवाब दिखाता है; गलत UPDATE या DELETE data नष्ट कर देता है। एक छूटी हुई condition shared test environment के सारे orders cancel कर सकती है, और ज़्यादातर clients हर statement को सफल होते ही commit कर देते हैं, यानी undo नहीं होता।
अनुशासन के साथ यही statements testing को तेज़ और गहरा बनाते हैं: seed script हर run को एक जैसा शुरुआती data देती है, एक UPDATE सेकंडों में expired subscription बना देता है, और जानबूझकर rule तोड़ने वाला statement दिखाता है कि database ख़ुद data की रक्षा करता है या नहीं।
INSERT: एक row या कई
INSERT नई rows जोड़ता है: पहले columns की list, फिर उसी क्रम में values। जो column आप छोड़ देते हैं उसे उसका DEFAULT मिलता है, या DEFAULT न हो तो NULL; बिना default वाला NOT NULL column statement को fail कर देता है। जब key database generate करता है, तो वह column छोड़ दें और नई row अपनी चुनी हुई value से ढूँढें, जैसे email।
Multi-row INSERT एक ही VALUES keyword के बाद कई value lists रखता है; PostgreSQL, MySQL, SQLite और SQL Server सभी इसे स्वीकार करते हैं। Statement atomic होता है: एक row भी rule तोड़े तो कोई row insert नहीं होती (MySQL में default InnoDB engine के साथ)।
- Columns नाम से लिखें: table के column क्रम पर टिका statement table बदलने पर टूट जाता है, या गलत columns भर देता है।
- Text और dates single quotes में, numbers और NULL बिना quotes के; text के अंदर का quote दो बार लिखा जाता है:
'O''Brien'। - Parents को children से पहले insert करें, क्योंकि हर foreign key जाँचती है कि parent मौजूद है (SQLite foreign keys तभी लागू करता है जब
PRAGMA foreign_keys = ONहो)।
-- Single-row INSERT: the column list, then the values in the same order
INSERT INTO customers (customer_id, email, full_name, created_at)
VALUES (9001, 'qa.sara@example.com', 'QA Sara Ahmed', '2026-09-01 09:00:00');
-- 1 row inserted
-- Multi-row INSERT: one statement, one list of values per row
INSERT INTO orders (order_id, customer_id, status, total_amount, created_at)
VALUES (9101, 9001, 'PENDING', 45.00, '2026-09-01 10:00:00'),
(9102, 9001, 'PENDING', 120.00, '2026-09-01 10:05:00'),
(9103, 9001, 'PAID', 80.00, '2026-09-02 09:30:00');
-- 3 rows inserted, or none: one bad row rejects the whole statement
-- A child row: order 9102 must already exist
INSERT INTO order_items (order_item_id, order_id, product_sku, quantity, unit_price)
VALUES (9201, 9102, 'SKU-100', 2, 60.00);UPDATE और DELETE: पहले rows गिनें
UPDATE मौजूदा rows के columns बदलता है और DELETE पूरी rows हटाता है। WHERE clause तय करता है कि कौन-सी rows प्रभावित होंगी; उसके बिना हर row प्रभावित होती है। थोड़ा-सा गलत WHERE और भी बुरा है, क्योंकि वह सही दिखता है: LIKE pattern जो सोचे से ज़्यादा match करे, = NULL जो कुछ भी match न करे, OR जो अपने AND से छूट जाए।
इसलिए पहले गिनें। वही WHERE rows दिखाने वाले SELECT में और SELECT COUNT(*) में चलाएँ, और count को task से अपेक्षित संख्या से मिलाएँ। फिर सिर्फ़ WHERE के ऊपर वाली lines बदलकर UPDATE या DELETE बनाएँ, और client जो rows-affected संख्या बताए उसे अपने count से मिलाएँ। दोनों अलग हों तो रुक जाएँ।
- psql
UPDATE 2print करता है, SQL Server(2 rows affected)। UPDATE के लिए MySQL rows matched और rows changed अलग बताता है, और default रूप से affected में सिर्फ़ वे rows गिनता है जिनकी value सच में बदली, इसलिए rows matched को अपने count से मिलाएँ। - Parent row delete करने से पहले उसके children गिनें: foreign key DELETE reject करती है या,
ON DELETE CASCADEहो तो, children भी delete कर देती है, और बताया गया count सिर्फ़ उसी table का होता है जिसका नाम आपने लिखा।
-- 1. The WHERE you intend, as a SELECT: look at the rows, then count them
SELECT order_id, status
FROM orders
WHERE customer_id = 9001 AND status = 'PENDING';
-- 9101 PENDING
-- 9102 PENDING
SELECT COUNT(*)
FROM orders
WHERE customer_id = 9001 AND status = 'PENDING';
-- 2, as expected: the test customer has two pending orders
-- 2. The same WHERE, only the lines above it changed
UPDATE orders
SET status = 'CANCELLED'
WHERE customer_id = 9001 AND status = 'PENDING';
-- rows affected: 2, equal to the count
-- 3. DELETE: count the children before removing the parent
SELECT COUNT(*) FROM order_items WHERE order_id = 9102; -- 1
DELETE FROM orders WHERE order_id = 9102;
-- rejected by the foreign key from order_items; with ON DELETE CASCADE
-- it would succeed, report 1 row and remove the item line as wellTransaction के अंदर rehearse करें: BEGIN … ROLLBACK
ज़्यादातर clients autocommit mode में शुरू होते हैं (अपने client की setting जाँच लें): हर statement सफल होते ही commit हो जाता है। BEGIN इसके बजाय transaction खोलता है: statements का ऐसा समूह जिसे database एक इकाई की तरह रखता है या undo करता है। उसके बाद के बदलाव आपके session को दिखते हैं, लेकिन दूसरे sessions, application समेत, उन्हें तब तक नहीं देखते जब तक COMMIT उन्हें स्थायी न कर दे; ROLLBACK सारे बदलाव रद्द कर देता है। यह default isolation level में होता है: isolation level वह setting है जो तय करती है कि दूसरे sessions अभी commit न हुए transaction का क्या देख सकते हैं; transactions और DB migrations की testing वाली guide इन levels को समझाती है। SQL Server BEGIN TRANSACTION लिखता है, और MySQL START TRANSACTION भी स्वीकार करता है।
Routine: SELECT से गिनें, BEGIN, बदलाव चलाएँ, rows affected को count से मिलाएँ, transaction के अंदर SELECT से result जाँचें, फिर कुछ भी अलग हो या आप सिर्फ़ rehearse कर रहे हों तो ROLLBACK। COMMIT सिर्फ़ तब करें जब हर संख्या match करे और बदलाव रखना ही हो।
यह सिर्फ़ test database पर करें: आपका अपना disposable database, या ऐसा shared environment जिसके owner ने, आम तौर पर QA lead या उसे चलाने वाली team ने, सहमति दी हो। Production data के बदलाव team की change process से होते हैं, tester के SQL client से नहीं।
- Application uncommitted rows नहीं देख सकता: नए data के साथ screen test करनी हो तो COMMIT करना होगा, और data वापस पहले जैसा करने की योजना बनानी होगी।
- खुला transaction अपनी बदली हुई rows को lock रखता है और उन्हें लिखने वालों को इंतज़ार कराता है: जल्दी ख़त्म करें।
- PostgreSQL में कोई भी error transaction को abort कर देता है; ROLLBACK तक हर अगला statement fail होता है।
- ROLLBACK सब कुछ undo नहीं करता: PostgreSQL, MySQL और SQL Server इस्तेमाल हो चुकी generated key values वापस नहीं देते, और MySQL में
TRUNCATEयाALTER TABLEखुले transaction को implicitly commit कर देते हैं।
Test data seed करना और constraint violations जानबूझकर कराना
Seeding test से पहले जाना-पहचाना data load करती है, ताकि test आपकी चुनी हुई state से शुरू हो। INSERT statements को tests के साथ seed script में रखें, और हर row पर QA- prefix, example.com वाले email या तय key range का निशान लगाएँ, ताकि script पहले अपनी rows delete कर सके, children पहले और parents बाद में।
SQL application को bypass करता है: हाथ से लिखी row उसकी validation, audit log और caches को छोड़ देती है। इससे states तक जल्दी पहुँचते हैं, जैसे 31 दिन पहले बना order, लेकिन ऐसा data भी बन सकता है जो product कभी नहीं बना सकता, इसलिए test case में लिखें कि कौन-सा data SQL से आया।
DML से database के अपने rules, यानी उसके constraints, भी test होते हैं: NOT NULL, primary key, UNIQUE, foreign keys और CHECK, यानी ऐसी शर्त जो हर row को पूरी करनी है, जैसे CHECK (quantity > 0)। ऐसा statement लिखें जो ठीक एक rule तोड़े और result पहले से बताएँ: constraint error के साथ reject, और कोई data नहीं बदला। Constraints INSERT की तरह UPDATE और DELETE की भी रक्षा करते हैं। हर कोशिश ROLLBACK से ख़त्म करें, ताकि rule न हो तो भी खराब data न बचे: जो statement सफल हो जाए, वही finding है।
-- One broken rule per transaction, on your own test database.
-- If a rule is missing, ROLLBACK still removes the bad data.
BEGIN;
UPDATE order_items SET quantity = 0 WHERE order_item_id = 9201;
-- expected: rejected by CHECK (quantity > 0); quantity stays 2
ROLLBACK;
BEGIN;
DELETE FROM customers WHERE customer_id = 9001;
-- expected: rejected by the foreign key from orders (9101 to 9103)
ROLLBACK;
BEGIN;
INSERT INTO customers (customer_id, email, full_name, created_at)
VALUES (9002, 'qa.sara@example.com', 'QA Copy', '2026-09-01 09:00:00');
-- expected: rejected by UNIQUE (email); still one row with this email
ROLLBACK;Worked example: data-fix script का rehearsal
एक ticket में data-fix script है जिसे developer production में चलाएगा: abandoned orders cancel करना, यानी 1 अगस्त से पहले के वे orders जो अब भी PENDING हैं और जिनका कोई captured payment नहीं। Ticket के मुताबिक़ तीन orders cancel होंगे: 1201, 1202 और 1205। Staging में production data की हाल की masked copy है, और उसका owner सहमत है कि आप script वहाँ rehearse करें, बशर्ते staging बाद में पहले जैसा रहे।
Script के अपने WHERE से पहले गिनने पर 4 आता है। उन rows को उनके payments के साथ list करने से वजह दिखती है: order 1188 PENDING है लेकिन उसका एक CAPTURED payment है, और script में payments पर कोई condition नहीं। अभी कुछ नहीं बदला, इसलिए आप रुकते हैं और report करते हैं।
- Finding 1: script एक paid order cancel कर देती। Developer
NOT EXISTS (SELECT 1 FROM payments …)जोड़ता है, एक subquery जो captured payment वाले orders को बाहर रखती है, और count 3 हो जाता है। NOT IN नहीं, NOT EXISTS, क्योंकि subquery एक भी NULL लौटाए तो NOT IN कुछ भी match नहीं करता। - Finding 2: order 1188 paid है लेकिन अब भी PENDING है। इसे अलग से report करें: यह payment flow में संभावित defect की ओर इशारा करता है।
- Rehearsal: 3 rows affected, count के बराबर; transaction के अंदर 1201, 1202 और 1205 CANCELLED हैं और control row 1188 अब भी PENDING; ROLLBACK के बाद चारों फिर PENDING हैं।
- Queries, counts और आख़िरी SELECT ticket में जाते हैं: production run पहले वही count दोहराता है और तभी आगे बढ़ता है जब वह अब भी match करे।
| Order | Script का WHEREपहली गिनती: 4 | सुधरा हुआ WHEREगिनती: 3 | UPDATE के बादtransaction के अंदर · 3 rows affected | ROLLBACK के बादstaging पहले जैसा |
|---|---|---|---|---|
1201PENDING · कोई payment नहीं | match हुई | match हुई | CANCELLED | PENDING |
1202PENDING · कोई payment नहीं | match हुई | match हुई | CANCELLED | PENDING |
1205PENDING · कोई payment नहीं | match हुई | match हुई | CANCELLED | PENDING |
1188PENDING · payment CAPTURED | match हुई: paid orderफ़ेल | match नहीं हुईपास | PENDINGcontrol row, नहीं बदलीपास | PENDING |
- UPDATE से बदली, सिर्फ़ transaction के अंदर दिखती है
- Outline वाली row: जिसे script को नहीं बदलना चाहिए
-- The developer's data-fix script, to run in production later:
-- UPDATE orders SET status = 'CANCELLED'
-- WHERE status = 'PENDING' AND created_at < '2026-08-01';
-- Ticket: "cancels 3 abandoned orders: 1201, 1202, 1205"
-- 1. Count first with the script's own WHERE
SELECT COUNT(*) FROM orders
WHERE status = 'PENDING' AND created_at < '2026-08-01';
-- 4, the ticket says 3: stop and list the rows with their payments
SELECT o.order_id, p.status AS payment
FROM orders o
LEFT JOIN payments p ON p.order_id = o.order_id
WHERE o.status = 'PENDING' AND o.created_at < '2026-08-01'
ORDER BY o.order_id;
-- 1188 CAPTURED <- paid, yet still PENDING
-- 1201 NULL
-- 1202 NULL
-- 1205 NULL
-- 2. The developer's fixed WHERE: count again
SELECT COUNT(*) FROM orders
WHERE status = 'PENDING' AND created_at < '2026-08-01'
AND NOT EXISTS (SELECT 1 FROM payments p
WHERE p.order_id = orders.order_id AND p.status = 'CAPTURED');
-- 3
-- 3. Rehearse on staging with the owner's agreement, then undo
BEGIN;
UPDATE orders SET status = 'CANCELLED'
WHERE status = 'PENDING' AND created_at < '2026-08-01'
AND NOT EXISTS (SELECT 1 FROM payments p
WHERE p.order_id = orders.order_id AND p.status = 'CAPTURED');
-- rows affected: 3, equal to the count
SELECT order_id, status FROM orders
WHERE order_id IN (1188, 1201, 1202, 1205);
-- 1188 PENDING, 1201 CANCELLED, 1202 CANCELLED, 1205 CANCELLED
ROLLBACK;
-- the same SELECT now shows all four orders PENDING againआम गलतियाँ
- WHERE को SELECT में चलाकर गिने बिना UPDATE या DELETE लिख देना।
- Rows-affected संख्या count से अलग होने पर भी आगे बढ़ जाना।
- Autocommit भूल जाना, जिससे experiment पहले ही स्थायी हो जाता है।
- Transaction खुला छोड़कर locked rows लिखने वाले सभी को रोक देना।
- Owner की सहमति के बिना shared test database बदलना, या ऐसी rows छूना जो आपने नहीं बनाईं।
- Application से uncommitted बदलाव देखने की उम्मीद करना, या ऐसे data से हुआ defect report करना जो सिर्फ़ SQL बना सकता है।
QA का नज़रिया
Team में database पर लिखने की अनुमति एक समझौते के साथ आती है: हर environment का owner कौन है, आप कौन-सी rows बदल सकते हैं (आम तौर पर सिर्फ़ अपनी), और environment reset कैसे होता है। जब test उसी रास्ते के बारे में हो तो data product या उसकी API से बनाएँ; SQL वहाँ इस्तेमाल करें जहाँ वह तेज़, ज़्यादा सटीक या अकेला रास्ता हो।
Data बदलने वाले statement को छोटी release की तरह लें: statement, अपेक्षित count, rows affected, जाँच और commit या rollback का फ़ैसला ticket या test case में जाते हैं। Developer की data fix या migration को भी इसी तरह rehearse करें; आपकी संख्याएँ असली run का acceptance check बन जाती हैं।
अभ्यास
Test data reset ठीक करें और rehearse करें
Points-expiry test से पहले test plan कहता है: "GOLD या SILVER tier के QA test customers के points 0 कर दें।" एक colleague ने नीचे UPDATE का draft लिखा है। QA lead सिर्फ़ उन rows को बदलने देता है जिनका email @qa.example.com पर ख़त्म होता है।
पता करें कि draft कौन-सी rows बदलेगा, उसे ठीक करें, rehearsal लिखें और CHECK constraint test करें।
Test plan: "GOLD या SILVER tier के QA test customers के points 0 कर दें।"
अनुमति: सिर्फ़ वे rows जिनका email @qa.example.com पर ख़त्म होता है
customers
customer_id email tier points
301 sara@qa.example.com GOLD 900
302 omar@qa.example.com SILVER 450
303 lina@qa.example.com BRONZE 120
304 fahad@partner.example.net SILVER 700
305 noura@qa.example.com SILVER 0
Constraint: CHECK (points >= 0)
Draft:
UPDATE customers
SET points = 0
WHERE email LIKE '%@qa.example.com' AND tier = 'GOLD' OR tier = 'SILVER';- Draft के WHERE को row-by-row जाँचें और matches गिनें।
- WHERE ठीक करें, count-first SELECT लिखें और अपेक्षित count बताएँ।
- BEGIN block लिखें: अपेक्षित rows affected, एक जाँच, और COMMIT या ROLLBACK कब करना है।
- ऐसा statement लिखें जो
CHECK (points >= 0)तोड़े, और उसका expected result बताएँ।
मॉडल उत्तर दिखाएँ
AND, OR से ज़्यादा मज़बूती से जुड़ता है, इसलिए draft का मतलब है (email LIKE '%@qa.example.com' AND tier = 'GOLD') OR tier = 'SILVER'। यह 4 rows match करता है: 301, 302, 304 और 305, जिनमें 304 भी है, एक partner का customer जिसे आप नहीं बदल सकते।
ठीक किया गया WHERE: WHERE email LIKE '%@qa.example.com' AND tier IN ('GOLD', 'SILVER')। इस WHERE के साथ SELECT COUNT(*) FROM customers 3 लौटाता है (301, 302 और 305)।
BEGIN;, फिर ठीक किया गया UPDATE: अपेक्षित 3 rows affected (MySQL default रूप से 2 rows affected बताता है, 3 matched और 2 changed के साथ, क्योंकि 305 के points पहले से 0 हैं: matched वाली संख्या ही आपके count के बराबर है)। Transaction के अंदर SELECT में 301, 302 और 305 पर 0, 303 पर 120 और 304 पर 700 दिखना चाहिए। COMMIT सिर्फ़ तब करें जब हर संख्या match करे, क्योंकि application सिर्फ़ committed data देखता है; वरना ROLLBACK।
BEGIN; UPDATE customers SET points = -1 WHERE customer_id = 303; ROLLBACK; Expected: CHECK constraint का नाम बताने वाले error के साथ reject, और 303 के 120 points बने रहते हैं। Statement सफल हो जाए तो constraint मौजूद नहीं है: उसे report करें; ROLLBACK -1 को data में रहने नहीं देता।
अक्सर पूछे जाने वाले सवाल
Test data SQL से बनाऊँ या application से?
जब test इस बारे में हो कि data कैसे बनता है, तो application या उसकी API को प्राथमिकता दें, क्योंकि वह रास्ता validation, auditing और events चलाता है। बड़े या दोहराए जाने वाले baselines seed करने, product से देर में पहुँचने वाली states तक पहुँचने और database rules को सीधे test करने के लिए SQL इस्तेमाल करें, और लिखें कि कौन-सा data SQL से आया।
क्या BEGIN … ROLLBACK में लपेटकर production में UPDATE चलाना सुरक्षित है?
नहीं। Uncommitted UPDATE भी उन rows को lock करता है जिन्हें असली users बदलना चाहते हैं, ROLLBACK की जगह गलती से लिखा COMMIT स्थायी होता है, और कुछ statements implicitly commit कर देते हैं। Production data आपकी team की approved change process से बदलता है; testers ऐसे बदलाव test database पर rehearse करते हैं, जैसे worked example में।
DELETE और TRUNCATE में क्या फ़र्क है?
DELETE वे rows हटाता है जो उसके WHERE से match करें; foreign keys और DELETE triggers (ऐसा code जो rows delete होने पर database अपने आप चलाता है) लागू होते हैं, और transaction उसे rollback कर सकता है। TRUNCATE पूरी table खाली करता है और WHERE नहीं लेता। यह DELETE triggers नहीं चलाता, दूसरी tables के reference करने पर reject या सीमित होता है, और MySQL में implicitly commit करता है। Shared database पर test rows हटाने के लिए WHERE के साथ DELETE इस्तेमाल करें।
संदर्भ
- ISO/IEC 9075-1:2023 — Information technology — Database languages SQL — Part 1: Framework (SQL/Framework)अंतरराष्ट्रीय SQL मानक का framework भाग, जिसे PostgreSQL, MySQL, SQLite आदि की बोलियाँ अलग-अलग हद तक लागू करती हैं।
- Transactions — PostgreSQL Documentationtransaction क्या है: कई क़दम जो BEGIN, COMMIT और ROLLBACK से सब-या-कुछ-नहीं लागू होते हैं, commit होने तक दूसरों को नहीं दिखते।
- SQL As Understood By SQLiteSQLite द्वारा स्वीकृत SQL व्याकरण, स्टेटमेंट दर स्टेटमेंट, सिंटैक्स डायग्राम के साथ।
- Constraints — PostgreSQL Documentationcheck, not-null, unique, primary key, foreign key और exclusion constraints — वे नियम जो डेटाबेस लागू करता है और टेस्टर जाँचता है।
Mutqan tools से अभ्यास करें
SQL स्टेटमेंट में सिंटैक्स की समस्याएँ, असंतुलित कोष्ठक, बिना बंद की स्ट्रिंग और जोखिम भरे पैटर्न जाँचें।
टेबल परिभाषा, नमूना पंक्तियों, CSV या JSON से INSERT स्टेटमेंट बनाएँ।
तालिका वाले डेटा को SQL VALUES सूची या VALUES-आधारित derived table में बदलें।
वैल्यू की सूची (हर लाइन पर एक या कॉमा से अलग) को कोट किए SQL IN (...) क्लॉज़ में बदलें।
किसी भी dialect के लिए वास्तविक जैसी टेस्ट पंक्तियों के साथ SQL seed स्क्रिप्ट (CREATE TABLE + INSERT) जनरेट करें।
CSV डेटा को अनुमानित कॉलम टाइप के साथ CREATE TABLE और INSERT स्टेटमेंट में बदलें।
और गहराई से
- टेस्टर्स के लिए SQLकुछ भी चलाने से पहले: सुरक्षित तरीका
- Transactions और DB migrations की टेस्टिंगAtomicity की टेस्टिंग: commit, rollback और failure injection
- QA इंजीनियरों के लिए डेटाबेस टेस्टिंगTest data: सिंथेटिक, seeded और reset करने योग्य
- QA इंजीनियरों के लिए डेटाबेस टेस्टिंगConstraints: डेटाबेस जो नियम लागू करता है
इस topic में आपकी प्रगति
प्रगति ट्रैक करने के लिए साइन इन करें
Topics पूर्ण चिह्नित करें, जहाँ छोड़ा था वहीं से जारी रखें और specialisation परीक्षाएँ खोलें।