DML I — INSERT, UPDATE, DELETE
DML — INSERT, UPDATE, DELETE
1. From DDL to DML — Now We Move Data
In Module 11 we built the empty shelves of our database. In this module we put things on the shelves,
move them around, and throw them away — using DML (Data Manipulation Language):
INSERT, UPDATE and DELETE. These three verbs change the actual rows
stored on disk, which means they are also the three statements that can destroy data — so we will
also learn how to wrap them in transactions to make every change reversible until we say
COMMIT.
INSERT, UPDATE, DELETE। এরাই row পরিবর্তন করে, তাই এরাই ডেটা নষ্ট-ও করতে পারে। এই কারণে transaction দিয়ে কীভাবে নিরাপদে কাজ করা যায়, সেটাও দেখব।
DDL → গঠন বদলায়। DML → ডেটা বদলায়। Transaction নিশ্চিত করে — একসাথে অনেকগুলো DML হয় সবগুলো হবে, না হলে কোনোটাই হবে না।
2. INSERT — Adding Rows
INSERT INTO adds new rows. There are three flavours you will use almost daily: single-row
insert, multi-row insert, and INSERT … SELECT. Pick the one that matches your task.
INSERT INTO দিয়ে নতুন row যোগ করা হয়। প্রতিদিনের কাজে তিনটি ধরন ব্যবহার হয় — single row, multi row, এবং অন্য table থেকে এসে INSERT … SELECT। কাজ অনুযায়ী সঠিকটি বেছে নিতে হবে।
2.1 — Single-row insert
-- Always list columns explicitly — never rely on column order.
INSERT INTO customers (name, phone, balance)
VALUES ('Rahim Uddin', '01711-100100', 1500.00);
SELECT * FROM customers;
INSERT INTO customers VALUES (…) works only as long as no one ever adds, removes
or rearranges a column. Listing names makes your code resilient to schema evolution.
Column-এর নাম না লিখলে কেউ schema পরিবর্তন করার সাথে সাথেই আপনার insert ভেঙে যাবে। তাই সবসময় column-এর নাম লেখা ভালো।
2.2 — Multi-row insert
-- One statement, three rows — much faster than three separate inserts.
INSERT INTO products (title, price, stock) VALUES
('Walton 1.5T AC', 42500, 8),
('Pran Mango Juice 1L', 95, 300),
('Square iSpring 5L', 3800, 14);
SELECT * FROM products;
2.3 — INSERT … SELECT (copy from another query)
Sometimes the data you want to insert already lives in another table — for example, an archive of last
month's bKash transactions. INSERT … SELECT lets you compute the rows on the fly:
-- Move only the November rows into the archive table
INSERT INTO bkash_archive_2024_11 (sender, amount, tx_date)
SELECT sender, amount, tx_date
FROM bkash_tx
WHERE tx_date LIKE '2024-11-%';
SELECT * FROM bkash_archive_2024_11;
3. UPDATE — Changing Existing Rows
UPDATE changes the values of existing rows. The structure is always UPDATE table SET col
= value [, col = value …] WHERE condition. The WHERE clause is critical: omit it and
you will update every single row in the table.
UPDATE দিয়ে existing row-এর value পরিবর্তন করা হয়। গঠনটি সবসময় — UPDATE table SET col = value WHERE condition। WHERE ছাড়া UPDATE চালালে সমস্ত row বদলে যাবে — এটিই database history-র সবচেয়ে বিখ্যাত ভুলগুলোর একটি।
-- Add 100 BDT to Karim's balance only.
UPDATE customers
SET balance = balance + 100
WHERE name = 'Karim';
SELECT * FROM customers;
UPDATE customers SET balance = 0; sets every customer's balance to zero.
This kind of one-character mistake has caused multi-crore losses at real fintech companies. Always preview
with a SELECT first.
UPDATE customers SET balance = 0; — এই query সব customer-এর balance শূন্য করে দেবে। বিশ্বের অনেক fintech কোম্পানি ঠিক এই রকম এক অক্ষরের ভুল থেকে কোটি টাকা হারিয়েছে। আগে SELECT দিয়ে দেখুন কোন কোন row পাল্টাবে।
3.1 — Preview-then-update pattern
-- Step 1 — preview affected rows
SELECT id, title, stock
FROM products
WHERE stock = 0;
-- Step 2 — only after the preview looks right, run the update
UPDATE products
SET title = title || ' (Out of stock)'
WHERE stock = 0;
SELECT * FROM products;
4. DELETE — Removing Rows
DELETE FROM table WHERE condition removes rows that match the predicate. Like UPDATE,
forgetting WHERE wipes the entire table. Unlike DROP, the table itself remains;
you can immediately insert new rows.
DELETE দিয়ে নির্দিষ্ট row মুছে ফেলা হয় — table নিজে রয়ে যায়। WHERE ভুলে গেলে পুরো table খালি হয়ে যাবে। তাই এই statement-ও খুব সাবধানে চালাতে হয়।
-- Remove all failed transactions older than the cleanup threshold.
DELETE FROM bkash_tx
WHERE status = 'failed';
SELECT * FROM bkash_tx;
4.1 — DELETE vs TRUNCATE — a recap
| Statement | Filterable? | Triggers fire? | Speed | SQLite support |
|---|---|---|---|---|
DELETE FROM t WHERE … | Yes | Yes | O(n) over matched rows | Yes |
DELETE FROM t (no WHERE) | No | Yes (per row) | O(1) optimised in SQLite | Yes — "truncate optimization" |
TRUNCATE TABLE t | No | Often skipped | O(1) | No — use DELETE FROM t |
5. ON CONFLICT — SQLite UPSERT
What if the row already exists? The classic problem: a mobile-recharge service receives the same callback
twice and tries to insert the same transaction id. You want the second attempt to update the row
instead of failing. SQLite (and PostgreSQL) solve this with INSERT … ON CONFLICT DO UPDATE,
commonly called UPSERT.
INSERT … ON CONFLICT DO UPDATE, যাকে UPSERT বলে। প্রথমবার insert হবে, পরবর্তী বার সেই row update হবে।
-- First webhook arrives — insert the row.
INSERT INTO recharges (tx_id, phone, amount)
VALUES ('TX-2024-0001', '01711-555555', 200)
ON CONFLICT(tx_id) DO UPDATE SET
attempts = recharges.attempts + 1;
-- Same webhook arrives a second time (network retry).
INSERT INTO recharges (tx_id, phone, amount)
VALUES ('TX-2024-0001', '01711-555555', 200)
ON CONFLICT(tx_id) DO UPDATE SET
attempts = recharges.attempts + 1;
SELECT * FROM recharges;
You can also write ON CONFLICT(col) DO NOTHING when you simply want to ignore duplicates:
INSERT INTO emails(addr) VALUES ('a@x.com')
ON CONFLICT(addr) DO NOTHING;
INSERT INTO emails(addr) VALUES ('a@x.com')
ON CONFLICT(addr) DO NOTHING;
SELECT COUNT(*) AS total FROM emails;
6. Transactions — BEGIN / COMMIT / ROLLBACK
A transaction groups several DML statements into a single all-or-nothing unit. The classic example is a bank transfer: deduct from sender, credit receiver. If the second statement fails, the first one must be undone — otherwise money disappears. SQL gives us three keywords for this:
| Keyword | Effect | বাংলায় |
|---|---|---|
BEGIN (or BEGIN TRANSACTION) | Starts a new transaction. | একটি নতুন transaction শুরু করে। |
COMMIT | Saves all changes made since BEGIN. | সব পরিবর্তন স্থায়ীভাবে সংরক্ষণ করে। |
ROLLBACK | Undoes everything since BEGIN. | সব পরিবর্তন বাতিল করে আগের অবস্থায় ফিরিয়ে দেয়। |
ROLLBACK করে সব আগের অবস্থায় ফিরিয়ে দিতে হবে।
-- Send 1500 BDT from Rahim to Karim — atomically.
BEGIN;
UPDATE accounts SET balance = balance - 1500 WHERE owner = 'Rahim';
UPDATE accounts SET balance = balance + 1500 WHERE owner = 'Karim';
COMMIT;
SELECT * FROM accounts;
And now a transaction we deliberately roll back — note that the balances do not change:
BEGIN;
UPDATE accounts SET balance = balance - 9999 WHERE owner = 'Rahim';
-- Realised the amount is wrong — undo everything.
ROLLBACK;
SELECT * FROM accounts;
7. The Production-Safe DML Checklist
✅ Always do (সবসময় করুন)
- List column names in every
INSERT. SELECTfirst to preview rows you willUPDATEorDELETE.- Wrap related changes in
BEGIN…COMMIT. - Use
ON CONFLICTfor retry-safe INSERTs. - Take a backup before bulk operations.
⚠️ Common DML disasters (বিপদ)
UPDATE t SET col = …with noWHERE.DELETE FROM twith noWHERE.- Mismatched column count in
VALUES. - Trusting a webhook to fire only once (no UPSERT).
- Forgetting
COMMIT— your changes never become visible to others.
"Write করার আগে read; পরিবর্তনের আগে wrap; নিশ্চিত হলে commit।"
8. Practice Problems
Each problem has a runnable answer. Try first, then click Show Answer.
-
Insert three students (name + email) into a
studentstable in one statement.এক statement-এ তিনজন student insert করুন।✨ Show Answer
ans1.sqlINSERT INTO students(name, email) VALUES ('Arif', 'arif@nsu.edu.bd'), ('Sanjida', 'sanjida@du.ac.bd'), ('Tanvir', 'tanvir@buet.ac.bd'); SELECT * FROM students; -
Increase every product's price by 10 percent in a
productstable.প্রতিটি product-এর price ১০% বাড়ান।✨ Show Answer
ans2.sqlUPDATE products SET price = price * 1.10; SELECT * FROM products; -
Delete every order whose
statusis'cancelled'.যেগুলোরstatus'cancelled' সেগুলো delete করুন।✨ Show Answer
ans3.sqlDELETE FROM orders WHERE status = 'cancelled'; SELECT * FROM orders; -
Use
INSERT … SELECTto copy all 'success' transactions into atx_successtable.INSERT … SELECTদিয়ে সব 'success' transactiontx_successtable-এ copy করুন।✨ Show Answer
ans4.sqlINSERT INTO tx_success(sender, amount) SELECT sender, amount FROM bkash_tx WHERE status = 'success'; SELECT * FROM tx_success; -
UPSERT a row keyed by
email: insert if new, otherwise increment avisitscounter.email-কে key ধরে UPSERT লিখুন; নতুন হলে insert, পুরোনো হলেvisitsবাড়ান।✨ Show Answer
ans5.sqlINSERT INTO visitors(email) VALUES ('rahim@x.com') ON CONFLICT(email) DO UPDATE SET visits = visitors.visits + 1; INSERT INTO visitors(email) VALUES ('rahim@x.com') ON CONFLICT(email) DO UPDATE SET visits = visitors.visits + 1; SELECT * FROM visitors; -
Implement a money transfer of 500 from Account 1 to Account 2 using a transaction.একটি transaction দিয়ে Account 1 থেকে Account 2-এ ৫০০ টাকা পাঠান।
✨ Show Answer
ans6.sqlBEGIN; UPDATE accounts SET balance = balance - 500 WHERE id = 1; UPDATE accounts SET balance = balance + 500 WHERE id = 2; COMMIT; SELECT * FROM accounts; -
Show that
ROLLBACKundoes an UPDATE.ROLLBACKযে UPDATE বাতিল করে দেখান।✨ Show Answer
ans7.sqlBEGIN; UPDATE t SET x = 9999; ROLLBACK; SELECT * FROM t; -
Use
ON CONFLICT DO NOTHINGto ignore duplicate phone numbers when bulk-inserting.Duplicate phone-গুলো এড়িয়ে যাবার জন্যON CONFLICT DO NOTHINGব্যবহার করুন।✨ Show Answer
ans8.sqlINSERT INTO contacts(phone, name) VALUES ('01711-1', 'A') ON CONFLICT(phone) DO NOTHING; INSERT INTO contacts(phone, name) VALUES ('01711-1', 'B') ON CONFLICT(phone) DO NOTHING; INSERT INTO contacts(phone, name) VALUES ('01911-2', 'C') ON CONFLICT(phone) DO NOTHING; SELECT * FROM contacts; -
Why does the database community say "every UPDATE without WHERE is a bug"? Two sentences."WHERE ছাড়া UPDATE সবসময় bug" — কেন? দুই বাক্যে ব্যাখ্যা।
✨ Show Answer
Answer: A WHERE-less UPDATE silently rewrites every row in the table, often touching millions of records that should not change. The intent was almost always "change one specific thing," so the absence of WHERE means the developer skipped saying which thing — a bug by definition.
WHERE-হীন UPDATE পুরো table-এর সব row বদলে দেয়, যেটা সাধারণত উদ্দেশ্য নয়। Developer সাধারণত একটিমাত্র row বদলাতে চান — WHERE না লিখলে সেটা বলা হয়নি, তাই এটা bug।
-
Increase by 50 the
stockof every product whosetitlestarts with 'Pran'.যাদের title 'Pran' দিয়ে শুরু — তাদেরstock৫০ বাড়ান।✨ Show Answer
ans10.sqlUPDATE products SET stock = stock + 50 WHERE title LIKE 'Pran%'; SELECT * FROM products; -
Delete the oldest 2 rows from a table by id (use a subquery).Subquery দিয়ে id অনুযায়ী সবচেয়ে পুরোনো ২টি row delete করুন।
✨ Show Answer
ans11.sqlDELETE FROM logs WHERE id IN ( SELECT id FROM logs ORDER BY id ASC LIMIT 2 ); SELECT * FROM logs; -
Insert a row that uses a
DEFAULTfor one column without naming the value.একটি column-এর জন্যDEFAULTব্যবহার করে row insert করুন।✨ Show Answer
ans12.sqlINSERT INTO notes(body) VALUES ('Hello'); SELECT * FROM notes; -
Use the
RETURNINGclause (SQLite 3.35+) to get back the row you just inserted.Insert-এর পরRETURNINGদিয়ে নতুন row ফেরত নিন।✨ Show Answer
ans13.sqlINSERT INTO users(name) VALUES ('Tania') RETURNING id, name; -
In two sentences, explain why you should always run
SELECTbeforeDELETEon production.Production-এDELETE-এর আগে কেনSELECTচালাবেন? দুই বাক্যে।✨ Show Answer
Answer: A SELECT preview shows exactly which rows will be touched, letting you spot a missing or wrong WHERE condition before any data is destroyed. Deleting the wrong rows in production often cannot be undone without restoring from backup, which costs hours and customer trust.
SELECT-এ আগে দেখলে বোঝা যায় ঠিক কোন কোন row delete হবে; ভুল WHERE হলে আগেই ধরা যায়। Production-এ ভুল row delete হলে backup থেকে restore ছাড়া উদ্ধার নেই, যেটা সময় এবং গ্রাহকের বিশ্বাস — দুটোই কাড়ে।
Summary — Module 12
DML changes data: INSERT adds rows, UPDATE changes values, DELETE
removes rows. Three habits make these statements safe in production: always list column names in
INSERT, always preview UPDATE/DELETE with a SELECT
first, and always wrap related changes in BEGIN … COMMIT so a single failure
can be undone with ROLLBACK. For idempotent inserts (webhooks, retries, sync jobs) use
SQLite's ON CONFLICT to UPSERT instead of failing.
INSERT, UPDATE, DELETE। নিরাপদে ব্যবহারের তিনটি অভ্যাস — column-এর নাম লেখা, SELECT দিয়ে preview করা, এবং BEGIN/COMMIT-এ মোড়ানো। Webhook ও retry-এর জন্য ON CONFLICT ব্যবহার করুন।