এই পর্বে যা শিখবেন
- SQL কেন “কী চাই” বলার ভাষা, আর এর কমান্ডগুলোর চারটি দল
- CREATE TABLE দিয়ে ডেটার ধরন আর নিয়মসহ টেবিল বানানো, INSERT দিয়ে ডেটা ঢোকানো
- SELECT, WHERE, ORDER BY, LIKE, GROUP BY, HAVING আর JOIN দিয়ে প্রশ্নের উত্তর বের করা — আর ডেটাবেস কোন ক্রমে সেটা করে
- UPDATE, DELETE আর transaction নিরাপদে ব্যবহার, আর SQL injection থেকে বাঁচার সঠিক পথ
- HSC ICT, চাকরির পরীক্ষা আর ইন্টারভিউর SQL প্রশ্ন, আর AI-এর লেখা SQL যাচাইয়ের নিয়ম
১ · SQL কী — ডেটাবেসকে প্রশ্ন করার ভাষা
পর্ব ৪১-এ আপনি দেখেছেন, একটি রিলেশনাল ডেটাবেস ডেটা রাখে টেবিলে — সারি আর কলামে — আর key দিয়ে টেবিলগুলোকে সম্পর্কে বাঁধে। কিন্তু ডেটা জমিয়ে রাখাই শেষ কথা নয়। একটি স্কুলের প্রধান শিক্ষক জানতে চান: “রাজশাহী জেলার যে ছাত্রদের GPA ৫, তাদের নাম বর্ণানুক্রমে দাও।” হিসাবরক্ষক জানতে চান: “কোন বিষয়ের গড় নম্বর সবচেয়ে কম?” এই প্রশ্নগুলো ডেটাবেসকে বোঝানোর ভাষার নাম SQL — Structured Query Language. উচ্চারণ দুইভাবেই চলে: “এস-কিউ-এল” বা “সিকুয়েল”।
SQL-এর সবচেয়ে বড় বৈশিষ্ট্য — এটি একটি declarative language. আপনি ফলাফলের বর্ণনা দেন, পদ্ধতির নয়:
SELECT name
FROM students
WHERE district = 'Rajshahi' AND gpa = 5
ORDER BY name;এখানে কোথাও লেখা নেই “প্রথম সারি থেকে শুরু করো, একটা একটা করে দেখো, মিললে একটি তালিকায় রাখো, শেষে তালিকা সাজাও”। পর্ব ৩৯-এর C প্রোগ্রামে এই ধাপগুলো লুপ দিয়ে নিজে লিখতে হতো। SQL-এ সেই কাজ করে ডেটাবেসের ভেতরের query optimizer — টেবিলে ৮ সারি থাকুক বা ৮০ লাখ, সে নিজেই দ্রুততম পথ বেছে নেয়।
রেস্তোরাঁয় গিয়ে আপনি বলেন, “এক প্লেট কাচ্চি, ঝাল কম।” আপনি রাঁধুনিকে বলেন না কোন হাঁড়িতে কতক্ষণ কী জ্বাল দিতে হবে — সেটা রান্নাঘরের দায়িত্ব। SQL হলো অর্ডার দেওয়ার ভাষা, আর ডেটাবেস হলো রান্নাঘর। একই অর্ডার ছোট দোকানে এক রকমভাবে, বড় হোটেলে আরেক রকমভাবে তৈরি হয় — কিন্তু আপনার অর্ডারের ভাষা বদলায় না।
আর সুখবর হলো, প্রতিদিনের কাজের বেশিরভাগই হয় হাতে গোনা কয়েকটি কমান্ডে। bKash-এর লেনদেনের ইতিহাস, বোর্ডের ফল প্রকাশের ওয়েবসাইট, ট্রেনের টিকিটের আসন, অনলাইন দোকানের অর্ডার — এসবের পেছনে কোনো না কোনো RDBMS, আর তাকে প্রশ্ন করা হয় SQL দিয়ে।
SQL কমান্ডের চারটি দল
| দল | কাজ | কমান্ড |
|---|---|---|
| DDL — Data Definition Language | টেবিলের কাঠামো বানানো, বদলানো, মোছা | CREATE, ALTER, DROP |
| DML — Data Manipulation Language | টেবিলের ভেতরের ডেটা যোগ, বদল, মোছা | INSERT, UPDATE, DELETE |
| DQL — Data Query Language | ডেটা পড়া, খোঁজা | SELECT |
| DCL — Data Control Language | কে কী করতে পারবে, সেই অনুমতি | GRANT, REVOKE |
অনেক পাঠ্যবইয়ে SELECT-কে DML-এর মধ্যেই ধরা হয়, আর COMMIT, ROLLBACK-কে কেউ কেউ আলাদা দল TCL (Transaction Control Language) বলেন। পরীক্ষায় যে বই অনুসরণ করছেন, তার শ্রেণিবিভাগটি মনে রাখুন — ধারণা একই।
আমাদের উদাহরণ — একটি স্কুলের ডেটাবেস
পুরো পর্ব জুড়ে একটি ছোট স্কুলের ডেটাবেস ব্যবহার করব। তিনটি টেবিল: students (রোল, নাম, জেলা, GPA), subjects (বিষয়ের কোড আর নাম), আর results (কোন রোল কোন বিষয়ে কত নম্বর পেয়েছে)। নামগুলো কাল্পনিক।
| roll | name | district | gpa |
|---|---|---|---|
| 101 | Rahim | Rajshahi | 5.00 |
| 102 | Karim | Dhaka | 4.50 |
| 103 | Nusrat | Rajshahi | 4.75 |
| 104 | Fatema | Khulna | 5.00 |
| 105 | Tanvir | Rajshahi | 3.80 |
| 106 | Sadia | Dhaka | 5.00 |
| 107 | Arif | Sylhet | 4.20 |
| 108 | Mitu | Khulna | NULL (নতুন ভর্তি, GPA এখনো নেই) |
subjects-এ তিনটি বিষয়: BAN (বাংলা), ENG (ইংরেজি), ICT. results-এ ১০১ থেকে ১০৬ রোলের প্রত্যেকের তিন বিষয়ের নম্বর — মোট ১৮টি সারি। ১০৭ আর ১০৮-এর কোনো ফল এখনো ঢোকানো হয়নি; JOIN শেখার সময় এটা কাজে লাগবে।
২ · টেবিল বানানো আর ডেটা ঢোকানো — CREATE TABLE আর INSERT
টেবিল বানানোর সময় তিনটি জিনিস ঠিক করতে হয়: কলামের নাম, প্রতিটি কলামের data type (কোন ধরনের মান থাকবে), আর constraint — এমন নিয়ম, যা ভুল ডেটা ঢুকতেই দেয় না।
CREATE TABLE students (
roll INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL,
district VARCHAR(30) NOT NULL DEFAULT 'Dhaka',
gpa DECIMAL(3,2) CHECK (gpa BETWEEN 0 AND 5)
);
CREATE TABLE subjects (
code CHAR(3) PRIMARY KEY,
title VARCHAR(40) NOT NULL UNIQUE
);
CREATE TABLE results (
roll INTEGER REFERENCES students(roll),
subject CHAR(3) REFERENCES subjects(code),
marks INTEGER CHECK (marks BETWEEN 0 AND 100),
PRIMARY KEY (roll, subject)
);| অংশ | মানে |
|---|---|
INTEGER / INT | পূর্ণসংখ্যা — রোল, নম্বর |
DECIMAL(3,2) | মোট ৩ অঙ্ক, দশমিকের পরে ২টি — যেমন 4.75. অনেক ডেটাবেসে REAL বা FLOAT-ও চলে |
CHAR(3) / VARCHAR(50) | লেখা। CHAR সবসময় ঠিক ৩ ঘর নেয়; VARCHAR সর্বোচ্চ ৫০, কিন্তু যতটুকু লাগে ততটুকুই |
DATE | তারিখ, যেমন '2026-10-19' (বছর-মাস-দিন) |
| PRIMARY KEY | প্রতিটি সারির অনন্য পরিচয়; ফাঁকা বা দুবার হতে পারে না। results-এ রোল আর বিষয় মিলে key — একই ছাত্রের একই বিষয়ের নম্বর দুবার ঢুকবে না |
| NOT NULL | মান দিতেই হবে |
| UNIQUE | একই মান দুবার নয় — দুটি বিষয়ের একই নাম হবে না |
| DEFAULT | মান না দিলে নিজে থেকে বসবে |
| CHECK | শর্ত মিথ্যা হলে সারি ঢুকবে না — ১৫০ নম্বর বা GPA ৬ অসম্ভব |
FOREIGN KEY (REFERENCES) | results-এর roll অবশ্যই students-এ থাকতে হবে — অস্তিত্বহীন ছাত্রের ফল ঢোকানো যাবে না |
পর্ব ১১-এর Excel-এর data validation-এর কথা মনে আছে? সেখানে নিয়ম ছিল পরামর্শের মতো — কপি-পেস্ট করে পাশ কাটানো যেত। ডেটাবেসের constraint আইন: কোনো পথেই নিয়ম ভাঙা ডেটা ঢোকে না, ডেটাবেস ত্রুটি দেখিয়ে কাজটি বাতিল করে।
কাঠামো বদলানো আর মোছা — ALTER আর DROP
ALTER TABLE students ADD COLUMN phone VARCHAR(15); -- নতুন কলাম যোগ
DROP TABLE subjects; -- পুরো টেবিল, ডেটাসহ, চিরতরে মুছে যায়-- দিয়ে শুরু অংশ SQL-এর মন্তব্য (comment); ডেটাবেস সেটা পড়ে না। DROP TABLE খুব শক্তিশালী কমান্ড — বাস্তব ডেটাবেসে এটি চালানোর আগে backup আছে কি না নিশ্চিত হন।
ডেটা ঢোকানো — INSERT INTO
INSERT INTO students (roll, name, district, gpa)
VALUES (101, 'Rahim', 'Rajshahi', 5.00);
-- একসাথে কয়েকটি সারি
INSERT INTO students (roll, name, district, gpa) VALUES
(102, 'Karim', 'Dhaka', 4.50),
(103, 'Nusrat', 'Rajshahi', 4.75);
-- district না দিলে DEFAULT বসবে: 'Dhaka'
INSERT INTO students (roll, name, gpa) VALUES (109, 'Joy', 4.00);INSERT INTO-তে কলামের নাম লিখে দেওয়া ভালো অভ্যাস — তাহলে পরে টেবিলে নতুন কলাম যোগ হলেও কমান্ডটি ভাঙে না, আর কোন মান কোন কলামে যাচ্ছে তা পড়েই বোঝা যায়। লেখা আর তারিখ থাকে একক উদ্ধৃতিচিহ্নে ('Rajshahi'), সংখ্যা উদ্ধৃতিচিহ্ন ছাড়া। এখন যদি কেউ (110, 'Rana', 'Bogura', 6.5) ঢোকাতে চান, CHECK নিয়মের কারণে ডেটাবেস তা প্রত্যাখ্যান করবে।
৩ · SELECT আর WHERE — যা চাই, শুধু সেটুকু
SELECT হলো SQL-এর সবচেয়ে বেশি ব্যবহৃত কমান্ড। সবচেয়ে সহজ রূপ:
SELECT * FROM students; -- সব কলাম, সব সারি
SELECT name, gpa FROM students; -- শুধু দুটি কলাম
SELECT name AS student_name, gpa * 20 AS percent
FROM students; -- নতুন নাম আর হিসাব করা কলাম* মানে “সব কলাম” — দ্রুত দেখে নেওয়ার জন্য সুবিধাজনক, কিন্তু প্রোগ্রামে শুধু দরকারি কলামগুলো নাম ধরে চাওয়াই ভালো। AS দিয়ে ফলাফলের কলামকে নতুন নাম দেওয়া যায়; একে বলে alias. SQL-এর কীওয়ার্ড (SELECT, FROM) বড় হাতের বা ছোট হাতের — দুটোই চলে; বড় হাতে লেখা শুধু পড়ার সুবিধার জন্য প্রচলিত রীতি। প্রতিটি বাক্যের শেষে ; দিন।
WHERE — সারি ছাঁকা
WHERE একটি শর্ত নেয়; যে সারিতে শর্ত সত্য, শুধু সেগুলোই থাকে। পর্ব ১৯-এর বুলিয়ান অ্যালজেব্রা এখানে সরাসরি কাজে লাগে — AND, OR আর NOT ঠিক সেভাবেই কাজ করে।
| অপারেটর | উদাহরণ | ফল (আমাদের টেবিলে) |
|---|---|---|
= <> < > <= >= | WHERE gpa >= 4.75 | Rahim, Nusrat, Fatema, Sadia (<> মানে “সমান নয়”; অনেক ডেটাবেসে !=-ও চলে) |
AND | WHERE district = 'Dhaka' AND gpa = 5 | Sadia |
OR | WHERE district = 'Khulna' OR district = 'Sylhet' | Fatema, Arif, Mitu |
NOT | WHERE NOT district = 'Rajshahi' | রাজশাহীর বাইরের ৫ জন |
BETWEEN … AND … | WHERE gpa BETWEEN 4 AND 4.8 | Karim, Nusrat, Arif (দুই সীমাও অন্তর্ভুক্ত) |
IN (…) | WHERE district IN ('Dhaka', 'Khulna') | Karim, Fatema, Sadia, Mitu |
LIKE | WHERE name LIKE 'S%' | Sadia |
IS NULL / IS NOT NULL | WHERE gpa IS NULL | Mitu |
AND আর OR একসাথে থাকলে AND আগে হিসাব হয় — যেমন গণিতে গুণ যোগের আগে। সন্দেহ থাকলে বন্ধনী দিন: WHERE (district = 'Dhaka' OR district = 'Khulna') AND gpa = 5 দেয় Fatema আর Sadia.
LIKE — ধাঁচ মিলিয়ে খোঁজা
LIKE-এ দুটি বিশেষ চিহ্ন (wildcard): % মানে “যেকোনো সংখ্যক অক্ষর, শূন্যও হতে পারে”, আর _ মানে “ঠিক একটি অক্ষর”।
name LIKE 'S%'— S দিয়ে শুরু: Sadia.name LIKE '%a'— a দিয়ে শেষ: Fatema, Sadia.name LIKE '%im%'— মাঝে কোথাও “im”: Rahim, Karim.name LIKE '_i%'— দ্বিতীয় অক্ষর i: Mitu.
বড়-ছোট হাতের অক্ষর নিয়ে সাবধান: SQLite আর MySQL-এ সাধারণত LIKE-এর কাছে 's' আর 'S' এক, কিন্তু PostgreSQL-এ আলাদা (সেখানে বড়-ছোট না মানতে ILIKE). Microsoft Access-এ এর বদলে * আর ? চিহ্ন ব্যবহৃত হয়।
NULL — শূন্য নয়, “অজানা”
Mitu-র GPA-র ঘরে NULL — মানে GPA এখনো জানা নেই। এটি ০ নয়, ফাঁকা লেখাও নয়। NULL-এর সাথে যেকোনো তুলনার ফল “সত্য” বা “মিথ্যা” নয়, “অজানা” — তাই WHERE gpa = NULL কোনো সারিই দেয় না! NULL খুঁজতে সবসময় IS NULL লিখুন। ভাবনার প্রশ্ন ৪-এ এর পেছনের গল্প আছে।
ডেটাবেস প্রশ্নটি কোন ক্রমে প্রক্রিয়া করে
আমরা লিখি SELECT দিয়ে শুরু করে, কিন্তু ডেটাবেস কাজ শুরু করে FROM থেকে। নিচের প্রশ্নটি ধাপে ধাপে দেখুন — প্রতি ধাপে টেবিল কীভাবে ছোট হয়, লক্ষ করুন:
roll name district gpa 101 Rahim Rajshahi 5.00 102 Karim Dhaka 4.50 103 Nusrat Rajshahi 4.75 104 Fatema Khulna 5.00 105 Tanvir Rajshahi 3.80 106 Sadia Dhaka 5.00 107 Arif Sylhet 4.20 108 Mitu Khulna NULL
roll name district gpa 101 Rahim Rajshahi 5.00 ✔ 102 Karim Dhaka 4.50 ✘ 103 Nusrat Rajshahi 4.75 ✔ 104 Fatema Khulna 5.00 ✘ 105 Tanvir Rajshahi 3.80 ✔ 106 Sadia Dhaka 5.00 ✘ 107 Arif Sylhet 4.20 ✘ 108 Mitu Khulna NULL ✘
roll name district gpa 101 Rahim Rajshahi 5.00 103 Nusrat Rajshahi 4.75 105 Tanvir Rajshahi 3.80
roll name district gpa 101 Rahim Rajshahi 5.00 103 Nusrat Rajshahi 4.75 105 Tanvir Rajshahi 3.80
name Rahim Nusrat Tanvir লেখার ক্রম: SELECT → FROM → WHERE → ORDER BY যৌক্তিক ক্রম: FROM → WHERE → SELECT → ORDER BY
- FROM আগে। ডেটাবেস প্রথমে জানতে চায় — কোন টেবিল?
students-এর আটটি সারিই এখন হাতে। কোন কলাম দেখাতে হবে, তা এখনো প্রশ্ন নয়। - WHERE ছাঁকে। প্রতিটি সারিতে শর্ত পরীক্ষা: district কি 'Rajshahi'? তিনটি সারি টিকে থাকে, পাঁচটি বাদ। বড় টেবিলে ডেটাবেস এখানে index ব্যবহার করে সব সারি না পড়েই মিলগুলো খুঁজে নিতে পারে।
- ORDER BY সাজায়। টিকে থাকা তিনটি সারি gpa অনুযায়ী বড় থেকে ছোট (DESC). লক্ষ করুন, gpa ফলাফলে দেখানো হবে না — তবু তা দিয়ে সাজানো যায়, কারণ এই মুহূর্তে পুরো সারি হাতে আছে।
- SELECT কলাম বাছে। এবার শুধু
nameকলাম রাখা হয়; বাকি কলাম ফেলে দেওয়া হয়। - ফলাফল। Rahim, Nusrat, Tanvir. মনে রাখার কৌশল: আগে টেবিল, তারপর সারি ছাঁকা, শেষে কলাম বাছাই আর সাজানো। এখানে বোঝার সুবিধার জন্য সাজানো আগে দেখানো হয়েছে; SQL-এর যৌক্তিক ক্রমে আসলে SELECT আগে, ORDER BY পরে — পুরো ক্রম: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT (তবু ORDER BY ফলাফলে না দেখানো কলাম দিয়েও সাজাতে পারে)। এজন্যই ORDER BY-তে SELECT-এর দেওয়া alias ব্যবহার করা যায়, কিন্তু WHERE-এ যায় না।
৪ · সাজানো, সীমা আর পুনরাবৃত্তি বাদ — ORDER BY, LIMIT, DISTINCT
ORDER BY ফলাফল সাজায়। ASC (ascending) মানে ছোট থেকে বড় — সংখ্যায় ১, ২, ৩; লেখায় A থেকে Z. DESC (descending) উল্টো। কিছু না লিখলে ডিফল্ট ASC — পরীক্ষায় এই প্রশ্নটি খুব আসে।
SELECT name, gpa FROM students
ORDER BY gpa DESC, name ASC; -- GPA বড় থেকে ছোট; সমান হলে নাম অনুযায়ী
SELECT name, gpa FROM students
WHERE gpa IS NOT NULL
ORDER BY gpa DESC
LIMIT 3; -- সেরা তিনজন
SELECT DISTINCT district FROM students
ORDER BY district; -- প্রতিটি জেলা একবারপ্রত্যাশিত আউটপুট (তৃতীয় প্রশ্ন):
| district |
|---|
| Dhaka |
| Khulna |
| Rajshahi |
| Sylhet |
- একাধিক কলামে সাজানো: প্রথম কলামে সমান হলে দ্বিতীয়টি দেখা হয়। Rahim, Fatema আর Sadia — তিনজনেরই GPA ৫; তাই নাম অনুযায়ী Fatema, Rahim, Sadia.
- LIMIT: প্রথম কয়টি সারি। ORDER BY ছাড়া LIMIT দিলে “কোন তিনটি” তা নিশ্চিত নয় — ডেটাবেস যেকোনো ক্রমে দিতে পারে। এখানে ৫.০০-এ তিনজন সমান, তাই সেরা তিনজন ঠিক এরাই। SQL Server আর Access-এ লেখা হয়
SELECT TOP 3 …. - DISTINCT: পুনরাবৃত্তি বাদ। আট সারিতে চারটি জেলা।
- NULL কোথায় বসে: SQLite আর MySQL-এ ASC সাজালে NULL সবার আগে আসে; PostgreSQL আর Oracle-এ সবার শেষে। এজন্যই ওপরে
WHERE gpa IS NOT NULLদিয়ে Mitu-কে আগেই বাদ দেওয়া হয়েছে।
ডেটাবেসের টেবিলে সারির কোনো নিশ্চিত ক্রম নেই। যে ফলাফলে ক্রম গুরুত্বপূর্ণ — মেধাতালিকা, রিপোর্ট, প্রথম ১০টি — সেখানে সবসময় ORDER BY লিখুন। আজ সঠিক ক্রমে আসছে বলে কাল আসবে, এমন নিশ্চয়তা নেই।
৫ · হিসাব করা — aggregate function, GROUP BY আর HAVING
অনেক সারি থেকে একটি সংখ্যা বের করার ফাংশনকে বলে aggregate function:
| ফাংশন | প্রশ্ন | উত্তর |
|---|---|---|
COUNT(*) | SELECT COUNT(*) FROM students; | 8 (সব সারি) |
COUNT(gpa) | SELECT COUNT(gpa) FROM students; | 7 (NULL গোনা হয় না) |
SUM | SELECT SUM(marks) FROM results WHERE roll = 101; | 255 |
AVG | SELECT AVG(marks) FROM results WHERE subject = 'ICT'; | 84.67 (প্রায়) |
MIN / MAX | SELECT MIN(marks), MAX(marks) FROM results; | 48, 95 |
COUNT(*) আর COUNT(gpa)-এর পার্থক্যটি লক্ষ করুন: aggregate function NULL মান উপেক্ষা করে। AVG(gpa)-ও Mitu-কে বাদ দিয়ে বাকি সাতজনের গড় করবে — Mitu-কে শূন্য ধরে আটজনে ভাগ করবে না।
GROUP BY — দলে দলে হিসাব
“প্রতিটি বিষয়ের গড় নম্বর” — একটি গড় নয়, বিষয়প্রতি একটি করে। GROUP BY একই মানের সারিগুলোকে এক দলে জড়ো করে, তারপর aggregate function প্রতিটি দলে আলাদাভাবে চলে। পর্ব ১১-এর Pivot Table মনে পড়ছে? একই ধারণা। আর দল তৈরি হওয়ার পরে দলগুলোকে ছাঁকতে লাগে HAVING:
roll subject marks roll subject marks 101 BAN 78 104 BAN 90 101 ENG 85 104 ENG 88 101 ICT 92 104 ICT 79 102 BAN 65 105 BAN 55 102 ENG 70 105 ENG 48 102 ICT 88 105 ICT 70 103 BAN 82 106 BAN 72 103 ENG 74 106 ENG 91 103 ICT 95 106 ICT 84
BAN │ 78 65 82 90 55 72 ENG │ 85 70 74 88 48 91 ICT │ 92 88 95 79 70 84
BAN │ 442 ÷ 6 = 73.67 ENG │ 456 ÷ 6 = 76.00 ICT │ 508 ÷ 6 = 84.67
subject avg BAN 73.67 ✘ (৭৫-এর কম) ENG 76.00 ✔ ICT 84.67 ✔
- কাঁচা ডেটা। ছয়জন ছাত্র × তিনটি বিষয় = ১৮টি সারি। এখান থেকে বিষয়প্রতি একটি গড় চাই।
- ঝুড়ি তৈরি। GROUP BY subject প্রতিটি আলাদা বিষয়ের জন্য একটি ঝুড়ি বানায়, আর প্রতিটি সারিকে তার বিষয়ের ঝুড়িতে ফেলে। ১৮টি সারি এখন তিনটি দলে। পরীক্ষার খাতা বিষয় অনুযায়ী তিনটি স্তূপে ভাগ করার মতো।
- প্রতিটি ঝুড়িতে হিসাব। AVG প্রতিটি দলে আলাদাভাবে চলে, আর প্রতিটি দল থেকে একটি করে সারি বের হয়। এখন থেকে SELECT-এ শুধু দুই ধরনের কলাম রাখা যায় — যা দিয়ে দল বানানো হয়েছে (subject), আর aggregate (AVG). রোল লিখলে প্রশ্ন ওঠে “কোন রোল?” — একটি দলে ছয়টি রোল আছে।
- HAVING দল ছাঁকে। গড় ৭৫-এর বেশি এমন বিষয় — ENG আর ICT. WHERE এখানে চলত না, কারণ WHERE কাজ করে দল তৈরির আগে, একেকটি সারির ওপর; তখনো কোনো গড়ই হিসাব হয়নি। নিয়ম: WHERE ছাঁকে সারি, HAVING ছাঁকে দল।
এবার পর্যন্ত যা শিখলেন, তা নিজে চালিয়ে দেখুন। নিচের ব্লকে আসল বিষয় SQL-এর লাইনগুলো — Python এখানে শুধু বাহক: সে মেমরিতে (":memory:") একটি অস্থায়ী SQLite ডেটাবেস বানায়, আমাদের দুটি টেবিল তৈরি করে, ডেটা ঢোকায়, তারপর পাঁচটি SELECT চালিয়ে ফল ছাপে। Python না জানলেও চলবে — ত্রিপল উদ্ধৃতিচিহ্নের (""") ভেতরের আর show(...)-এর দ্বিতীয় অংশের SQL পড়ুন। SQL বদলে আবার চালিয়ে দেখুন।
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript("""
CREATE TABLE students (roll INTEGER PRIMARY KEY, name TEXT NOT NULL,
district TEXT NOT NULL, gpa REAL CHECK (gpa BETWEEN 0 AND 5));
CREATE TABLE results (roll INTEGER REFERENCES students(roll), subject TEXT,
marks INTEGER CHECK (marks BETWEEN 0 AND 100), PRIMARY KEY (roll, subject));
INSERT INTO students VALUES (101,'Rahim','Rajshahi',5.0), (102,'Karim','Dhaka',4.5),
(103,'Nusrat','Rajshahi',4.75), (104,'Fatema','Khulna',5.0), (105,'Tanvir','Rajshahi',3.8),
(106,'Sadia','Dhaka',5.0), (107,'Arif','Sylhet',4.2), (108,'Mitu','Khulna',NULL);
INSERT INTO results VALUES (101,'BAN',78),(101,'ENG',85),(101,'ICT',92),(102,'BAN',65),
(102,'ENG',70),(102,'ICT',88),(103,'BAN',82),(103,'ENG',74),(103,'ICT',95),(104,'BAN',90),
(104,'ENG',88),(104,'ICT',79),(105,'BAN',55),(105,'ENG',48),(105,'ICT',70),(106,'BAN',72),
(106,'ENG',91),(106,'ICT',84);""")
def show(title, sql):
print("--", title)
for row in db.execute(sql): print(*row, sep=" | ")
show("WHERE + ORDER BY", "SELECT name, gpa FROM students WHERE district = 'Rajshahi' ORDER BY gpa DESC")
show("LIKE '%a'", "SELECT roll, name FROM students WHERE name LIKE '%a' ORDER BY roll")
show("IS NULL", "SELECT name FROM students WHERE gpa IS NULL")
show("COUNT per district", "SELECT district, COUNT(*) FROM students GROUP BY district ORDER BY district")
show("AVG per subject", "SELECT subject, ROUND(AVG(marks), 2) FROM results GROUP BY subject ORDER BY subject")আউটপুটের প্রথম অংশ Rahim | 5.0, Nusrat | 4.75, Tanvir | 3.8 — ঠিক প্রথম stepper-এর ফল (Python দশমিকের শেষের শূন্য দেখায় না)। LIKE দেয় 104 | Fatema আর 106 | Sadia; IS NULL দেয় Mitu. জেলাভিত্তিক গণনা: Dhaka | 2, Khulna | 2, Rajshahi | 3, Sylhet | 1. শেষে বিষয়ভিত্তিক গড়: BAN | 73.67, ENG | 76.0, ICT | 84.67 — দ্বিতীয় stepper-এর সাথে মিলিয়ে নিন। প্রতিটি প্রশ্নে ORDER BY থাকায় ফল প্রতিবার একই ক্রমে আসে। চেষ্টা করুন: শেষ প্রশ্নে HAVING AVG(marks) > 75 যোগ করুন (GROUP BY-এর পরে, ORDER BY-এর আগে), বা একটি INSERT-এ marks 150 দিয়ে দেখুন CHECK কী ত্রুটি দেখায়।
৬ · JOIN — দুই টেবিল মেলানো
পর্ব ৪১-এ দেখেছেন, normalization-এর জন্য ছাত্রের নাম আর ফলাফল আলাদা টেবিলে রাখা হয় — results-এ শুধু রোল। কিন্তু রিপোর্টে তো নাম চাই! JOIN দুই টেবিলের সারিগুলোকে একটি মিলের শর্তে (এখানে রোল) পাশাপাশি জুড়ে দেয়। ভাবুন, ভর্তির রেজিস্টার খাতা আর নম্বরের খাতা পাশাপাশি রেখে রোল মিলিয়ে নাম বসানো — Excel-এর XLOOKUP যা করত, তাই।
SELECT s.name, r.marks
FROM students AS s
INNER JOIN results AS r ON s.roll = r.roll
WHERE r.subject = 'ICT'
ORDER BY r.marks DESC;students AS s — টেবিলের ছোট নাম (alias), যাতে বারবার পুরো নাম লিখতে না হয়। s.roll মানে students-এর roll; দুই টেবিলেই roll আছে, তাই কোনটি তা বলে দিতে হয়। ON-এর পরে মিলের শর্ত।
students (s) results (r) roll name roll marks 101 Rahim 101 92 102 Karim 102 88 103 Nusrat 103 95 104 Fatema 104 79 105 Tanvir 105 70 106 Sadia 106 84 107 Arif 108 Mitu
101 Rahim ═══ 101 92 102 Karim ═══ 102 88 103 Nusrat ═══ 103 95 104 Fatema ═══ 104 79 105 Tanvir ═══ 105 70 106 Sadia ═══ 106 84 107 Arif ─── ? (মিল নেই) 108 Mitu ─── ? (মিল নেই)
name marks
Nusrat 95
Rahim 92
Karim 88
Sadia 84
Fatema 79
Tanvir 70
(Arif আর Mitu নেই — মিল না পাওয়া সারি বাদ)
name marks Rahim 92 ... ... Sadia 84 Arif NULL Mitu NULL + WHERE r.roll IS NULL → Arif, Mitu (যাদের ফল এখনো ঢোকানো হয়নি)
- দুটি খাতা। বাঁয়ে আটজন ছাত্র, ডানে ICT-র ছয়টি নম্বর। নাম আছে এক টেবিলে, নম্বর অন্যটিতে — যোগসূত্র শুধু রোল।
- মিল খোঁজা।
ON s.roll = r.roll: প্রতিটি ছাত্রের রোলের সাথে নম্বরের খাতার রোল মেলানো হয়। ছয়জনের জোড়া পাওয়া গেল; Arif আর Mitu-র কোনো জোড়া নেই। - INNER JOIN. INNER JOIN শুধু জোড়া পাওয়া সারিগুলো রাখে — দুই টেবিলেই যাদের অস্তিত্ব আছে। শুধু
JOINলিখলেও INNER JOIN বোঝায়। - LEFT JOIN. LEFT JOIN বাঁ দিকের টেবিলের (students) সবাইকে রাখে; জোড়া না পেলে ডানের কলামে NULL বসায়। এর সাথে
WHERE r.roll IS NULLদিলে ঠিক তারাই আসে, যাদের ফল নেই — “কার নম্বর এখনো জমা হয়নি?” প্রশ্নের উত্তর।
ভুল JOIN-এ সংখ্যা ফুলে ওঠে: ICT-র শর্ত (WHERE r.subject = 'ICT') বাদ দিলে প্রতিটি ছাত্রের তিনটি করে সারি আসবে — ১৮টি। তখন SUM(s.gpa) করলে প্রতিটি GPA তিনবার যোগ হবে, নীরবে। আর ON-এর শর্তই ভুলে গেলে প্রতিটি ছাত্র প্রতিটি নম্বরের সাথে জুড়ে যায় — ৮ × ১৮ = ১৪৪টি অর্থহীন সারি। JOIN-এর পরে সারির সংখ্যা যা আশা করেছিলেন, তার সাথে মিলিয়ে দেখার অভ্যাস করুন।
৭ · ডেটা বদলানো আর মোছা — UPDATE, DELETE আর transaction
-- খাতা পুনর্নিরীক্ষায় Tanvir-এর ICT নম্বর ৭০ থেকে ৭৫
UPDATE results
SET marks = 75
WHERE roll = 105 AND subject = 'ICT';
-- ভুল করে ঢোকানো একটি সারি মোছা
DELETE FROM results
WHERE roll = 105 AND subject = 'ENG';UPDATE-এর গঠন: কোন টেবিল, SET দিয়ে কোন কলামে কী মান, আর WHERE দিয়ে কোন সারিগুলোতে। DELETE-এ শুধু টেবিল আর WHERE. দুটিরই সবচেয়ে বিপজ্জনক অংশ — WHERE ঐচ্ছিক। না লিখলে ডেটাবেস ধরে নেয় “সব সারি”, আর কোনো প্রশ্ন না করে কাজটা করে ফেলে।
DELETE FROM results
WHERE roll = 105 AND subject = 'ENG';
105 BAN 55
105 ENG 48 ← মুছে গেল
105 ICT 70
... বাকি ১৭টি সারি অক্ষত
ফল: 1 row deleted
DELETE FROM results; ← WHERE নেই! ১৮টি সারির সবগুলো মুছে গেল টেবিল আছে, কাঠামো আছে — ডেটা নেই ফল: 18 rows deleted (কোনো সতর্কবার্তা নেই)
SELECT COUNT(*) FROM results
WHERE roll = 105 AND subject = 'ENG';
→ 1 ✔ ঠিক যা আশা করেছি
এবার একই WHERE দিয়ে:
DELETE FROM results
WHERE roll = 105 AND subject = 'ENG';
BEGIN; DELETE FROM results; → 18 rows (১-এর বদলে!) ROLLBACK; → সব ফিরে এলো BEGIN; DELETE FROM results WHERE roll = 105 AND subject = 'ENG'; → 1 row COMMIT; → স্থায়ী হলো
- যা চেয়েছিলেন। Tanvir-এর ইংরেজির একটি ভুল সারি মুছতে হবে। WHERE-এর দুটি শর্ত মিলে ঠিক একটি সারি চিহ্নিত করে — রোল আর বিষয় মিলেই তো primary key.
- WHERE ভুলে গেলে। তাড়াহুড়োয় প্রথম লাইন লিখেই Enter চাপলেন। ডেটাবেস “আপনি কি নিশ্চিত?” জিজ্ঞেস করে না — ১৮টি সারিই মুছে যায়। DROP TABLE-এর মতো টেবিল হারায় না, কিন্তু ডেটা শেষ। UPDATE-এ WHERE ভুললে সব ছাত্রের নম্বর একসাথে ৭৫ হয়ে যেত।
- আগে SELECT. পেশাদারদের অভ্যাস: যে WHERE দিয়ে বদলাবেন বা মুছবেন, আগে সেটাই দিয়ে SELECT চালিয়ে দেখুন কতগুলো আর কোন সারি আসে। মিললে তারপর DELETE বা UPDATE.
- transaction.
BEGINদিয়ে শুরু করলে বদলগুলো সাময়িক থাকে। ফলাফলের সারিসংখ্যা অপ্রত্যাশিত হলেROLLBACK— সব আগের মতো। ঠিক থাকলেCOMMIT— স্থায়ী। (কিছু টুল নিজে নিজে প্রতিটি বাক্য commit করে, তখন এই সুরক্ষা থাকে না; তাই backup-ও জরুরি।)
Transaction — হয় সব, নয় কিছুই না
bKash-এ আপনি ৫০০ টাকা পাঠালেন। ডেটাবেসে দুটি কাজ: আপনার হিসাব থেকে ৫০০ কাটা, প্রাপকের হিসাবে ৫০০ জমা। প্রথমটির পরে যদি বিদ্যুৎ চলে যায়? টাকা কাটা হলো, কিন্তু কোথাও জমা হলো না! transaction এই দুটি কাজকে একটি অবিভাজ্য গুচ্ছ বানায়: BEGIN → দুটি UPDATE → COMMIT. মাঝপথে কিছু ভুল হলে ROLLBACK, আর ডেটাবেস নিশ্চিত করে — হয় দুটিই ঘটবে, নয়তো একটিও না। COMMIT হওয়ার পরে বিদ্যুৎ গেলেও বদল হারায় না, আর ROLLBACK সব বাতিল করে। এই নিশ্চয়তাগুলোর সংক্ষিপ্ত নাম ACID (Atomicity, Consistency, Isolation, Durability) — ব্যাংক আর মোবাইল ব্যাংকিং ডেটাবেসের ভিত্তি।
দ্বিতীয় চালানোর মতো উদাহরণে JOIN, “WHERE ভুলে যাওয়া DELETE”-কে ROLLBACK দিয়ে বাঁচানো, UPDATE-এর পরে COMMIT, আর ব্যবহারকারীর দেওয়া মান নিরাপদে পাঠানো — সব একসাথে। আবারও, Python শুধু বাহক; ত্রিপল উদ্ধৃতিচিহ্ন আর execute("...")-এর ভেতরের SQL-ই আসল:
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript("""
CREATE TABLE students (roll INTEGER PRIMARY KEY, name TEXT, district TEXT, gpa REAL);
CREATE TABLE results (roll INTEGER REFERENCES students(roll), subject TEXT, marks INTEGER);
INSERT INTO students VALUES (101,'Rahim','Rajshahi',5.0), (102,'Karim','Dhaka',4.5),
(103,'Nusrat','Rajshahi',4.75), (104,'Fatema','Khulna',5.0), (105,'Tanvir','Rajshahi',3.8),
(106,'Sadia','Dhaka',5.0), (107,'Arif','Sylhet',4.2), (108,'Mitu','Khulna',NULL);
INSERT INTO results VALUES (101,'ICT',92), (102,'ICT',88), (103,'ICT',95),
(104,'ICT',79), (105,'ICT',70), (106,'ICT',84);""")
print("INNER JOIN:", db.execute("""SELECT s.name, r.marks FROM students AS s
INNER JOIN results AS r ON s.roll = r.roll ORDER BY r.marks DESC LIMIT 3""").fetchall())
print("LEFT JOIN, no result:", db.execute("""SELECT s.name, r.marks FROM students AS s
LEFT JOIN results AS r ON s.roll = r.roll WHERE r.roll IS NULL ORDER BY s.roll""").fetchall())
cur = db.execute("DELETE FROM results") # WHERE forgotten!
print("deleted", cur.rowcount, "rows -> ROLLBACK")
db.rollback() # undo the whole transaction
db.execute("UPDATE results SET marks = 75 WHERE roll = 105 AND subject = 'ICT'")
db.commit() # make it permanent
print(db.execute("""SELECT s.name, r.marks FROM students AS s JOIN results AS r
ON s.roll = r.roll WHERE s.roll = ?""", (105,)).fetchone()) # 105: from a web form
print("rows in results:", db.execute("SELECT COUNT(*) FROM results").fetchone()[0])প্রথম লাইন INNER JOIN: [('Nusrat', 95), ('Rahim', 92), ('Karim', 88)] — ICT-র সেরা তিনজন (LIMIT 3). দ্বিতীয় লাইন LEFT JOIN, no result: [('Arif', None), ('Mitu', None)] — Python-এ SQL-এর NULL দেখায় None. তারপর deleted 6 rows -> ROLLBACK: WHERE ছাড়া DELETE সব ছয়টি সারি মুছেছিল, কিন্তু Python-এর sqlite3 নিজে থেকেই DELETE-এর আগে একটি transaction খুলেছিল (BEGIN), তাই rollback() সব ফিরিয়ে আনে। এরপর UPDATE আর commit(), আর ('Tanvir', 75) দেখায় বদলটি হয়েছে। শেষ লাইন rows in results: 6 — একটিও সারি হারায়নি। লক্ষ করুন WHERE s.roll = ?: রোলের মান SQL-এর লেখার সাথে জোড়া দেওয়া হয়নি, ? চিহ্নের জায়গায় আলাদা করে পাঠানো হয়েছে। কেন, তা পরের অংশে।
View আর index — এক লাইনে
- View: একটি SELECT-কে নাম দিয়ে সংরক্ষণ —
CREATE VIEW ict_marks AS SELECT …;তারপরSELECT * FROM ict_marks;যেন একটি টেবিল। জটিল প্রশ্ন বারবার না লিখতে, আর কাউকে টেবিলের শুধু কিছু কলাম দেখাতে কাজে লাগে। - Index:
CREATE INDEX idx_district ON students(district);— বইয়ের শেষের নির্ঘণ্টের মতো, যাতে জেলা দিয়ে খুঁজতে পুরো টেবিল পড়তে না হয়। পড়া দ্রুত হয়, কিন্তু প্রতিটি INSERT/UPDATE-এ index-ও হালনাগাদ করতে হয় বলে লেখা একটু ধীর হয়।
৮ · নানা ডেটাবেসের SQL, নিরাপত্তা আর অনুশীলনের জায়গা
একই ভাষা, নানা উচ্চারণ — SQL dialect
SQL-এর একটি আন্তর্জাতিক মান (ANSI/ISO standard) আছে, কিন্তু প্রতিটি ডেটাবেস সফটওয়্যার তার সাথে কিছু নিজস্ব সংযোজন করে — একে বলে SQL dialect. ভালো খবর: এই পর্বের প্রায় সবকিছু সবখানে একইভাবে চলে।
| ডেটাবেস | কোথায় দেখা যায় | ছোট পার্থক্যের উদাহরণ |
|---|---|---|
| MySQL / MariaDB | ওয়েবসাইট, WordPress, cPanel হোস্টিং | LIMIT 3; AUTO_INCREMENT |
| PostgreSQL | বড় ওয়েব অ্যাপ, সরকারি-বেসরকারি সিস্টেম | LIKE বড়-ছোট হাতের অক্ষর মানে; ILIKE |
| SQLite | মোবাইল অ্যাপ, ব্রাউজার, ছোট প্রোগ্রাম — সার্ভার লাগে না | ডেটার ধরন নমনীয়; foreign key চালু করতে আলাদা সেটিং |
| Microsoft SQL Server | ব্যাংক, কর্পোরেট অফিস | SELECT TOP 3 … |
| Oracle | বড় ব্যাংক, টেলিকম | FETCH FIRST 3 ROWS ONLY |
| Microsoft Access | ছোট অফিসের ডেস্কটপ ডেটাবেস | LIKE-এ * আর ?; ক্লিক করে query বানানোর ডিজাইন ভিউ |
SQL injection — কেন ব্যবহারকারীর লেখা কখনো SQL-এর সাথে জোড়া দেবেন না
ধরুন একটি ওয়েবসাইটে ছাত্র রোল লিখে ফল দেখেন। প্রোগ্রামার যদি ব্যবহারকারীর লেখা সরাসরি SQL বাক্যের লেখার সাথে জুড়ে দেন (string concatenation), তাহলে ডেটাবেস বুঝতে পারে না কোন অংশ প্রোগ্রামারের কমান্ড আর কোন অংশ ব্যবহারকারীর ডেটা। কেউ রোলের ঘরে সংখ্যার বদলে SQL-এর অংশের মতো দেখতে কিছু লিখলে সেটাও কমান্ড হিসেবে চলে যেতে পারে — অন্যের তথ্য দেখা, এমনকি টেবিল মুছে ফেলা পর্যন্ত। এই দুর্বলতার নাম SQL injection, আর এটি দুই দশকের বেশি সময় ধরে ওয়েবের সবচেয়ে ক্ষতিকর ত্রুটিগুলোর একটি।
সমাধান সহজ আর একটাই: parameterized query (prepared statement নামেও পরিচিত)। SQL বাক্যে মানের জায়গায় একটি চিহ্ন (? বা :roll) রাখুন, আর মান আলাদাভাবে পাঠান। ডেটাবেস আগে বাক্যের কাঠামো বুঝে নেয়, তারপর মানটিকে শুধু ডেটা হিসেবে বসায় — ভেতরে যা-ই লেখা থাকুক, সেটা কখনো কমান্ড হয় না।
# নিরাপদ পথ: মান যায় আলাদাভাবে, SQL-এর লেখা কখনো জোড়া দেওয়া হয় না
roll = form_input # ব্যবহারকারী যা লিখেছেন
row = db.execute("SELECT name, gpa FROM students WHERE roll = ?", (roll,)).fetchone()প্রায় সব ভাষায় একই ব্যবস্থা আছে — PHP-র PDO, Java-র PreparedStatement, Node.js-এর লাইব্রেরিগুলো। নিয়মটি মুখস্থ রাখুন: ব্যবহারকারীর দেওয়া কোনো মান কখনো জোড়া দিয়ে SQL বানাবেন না, সবসময় parameter হিসেবে পাঠাবেন। পাশাপাশি ওয়েবসাইটের ডেটাবেস-অ্যাকাউন্টকে শুধু দরকারি অনুমতি দিন (DCL-এর GRANT দিয়ে) — ফল দেখানোর পাতার DELETE বা DROP-এর অধিকার লাগে না। সাইবার নিরাপত্তার বড় ছবি পর্ব ৪৩-এ।
কোথায় অনুশীলন করবেন
- DB Browser for SQLite: বিনামূল্যের ওপেন সোর্স ডেস্কটপ প্রোগ্রাম (Windows, macOS, Linux). একটি ফাইলে ডেটাবেস বানান, “Execute SQL” ট্যাবে প্রশ্ন লিখে চালান, টেবিল চোখে দেখুন। ইন্টারনেট ছাড়াই চলে।
- অনলাইন SQL playground: ব্রাউজারেই SQL চালানোর অনেক ওয়েবসাইট আছে — “online SQL editor” বা “SQL fiddle” লিখে খুঁজুন। কিছু ইনস্টল করতে হয় না; শুধু গোপন বা আসল ডেটা সেখানে দেবেন না।
- Microsoft Access: যাঁদের কম্পিউটারে Office-এর সাথে আছে, Create → Query Design থেকে SQL View-এ গিয়ে SQL লিখতে পারেন।
- এই পর্বের দুটি চালানোর মতো ব্লক: ওপরের SQL লাইনগুলো বদলে বারবার চালান — ভুল করলে কিছুই নষ্ট হয় না, প্রতিবার নতুন ডেটাবেস তৈরি হয়।
আরও গভীরে: এখানে আপনি SQL-এর মূল অংশ দেখলেন। subquery, এক টেবিলের নিজের সাথে join (self join), window function, ER ডায়াগ্রাম থেকে টেবিল নকশা, normalization-এর গভীর রূপ আর transaction-এর isolation level শিখতে দেখুন ABCL TECH-এর DBMS ও SQL কোর্স. আর প্রোগ্রাম থেকে ডেটাবেস ব্যবহার — connection, commit, parameterized query আর migration — হাতে-কলমে শিখতে Python কোর্সের SQLite পর্ব.
পরীক্ষা ও ইন্টারভিউতে: HSC ICT, বিভিন্ন চাকরির কম্পিউটার অংশ আর জুনিয়র ডেভেলপারের ইন্টারভিউতে এ ধরনের প্রশ্ন প্রায়ই আসে —
- SQL-এর পূর্ণরূপ কী? — Structured Query Language.
- DDL আর DML-এর দুটি করে কমান্ড বলুন। — DDL: CREATE, ALTER, DROP; DML: INSERT, UPDATE, DELETE.
- টেবিল পুরোপুরি মুছতে কোন কমান্ড, আর শুধু সারি মুছতে কোনটি? — DROP TABLE কাঠামোসহ সব মোছে; DELETE শুধু সারি মোছে, টেবিল থাকে। (TRUNCATE-ও সব সারি মোছে, দ্রুত — তবে সব ডেটাবেসে নেই।)
- WHERE-এর কাজ কী? — শর্ত দিয়ে সারি ছাঁকা; শুধু শর্ত সত্য হওয়া সারিতে SELECT, UPDATE বা DELETE কাজ করে।
- ORDER BY-এর ডিফল্ট ক্রম কী? — ASC, অর্থাৎ ছোট থেকে বড়। আর WHERE বনাম HAVING: WHERE সারি ছাঁকে, HAVING GROUP BY-এর পরে দল ছাঁকে।
৯ · AI-এর যুগে — SQL লেখে AI, চালানোর আগে যাচাই আপনার
ChatGPT, Gemini, Claude বা Copilot-কে বাংলায় বললেই — “প্রতিটি জেলার GPA ৫ পাওয়া ছাত্রের সংখ্যা দাও” — কয়েক সেকেন্ডে সঠিক দেখতে SQL লিখে দেয়। পড়তে নিখুঁত, চালালে ত্রুটিও দেখায় না। কিন্তু ভুল SQL প্রায়ই ত্রুটি দেয় না — ভুল ফল দেয়, অথবা ভুল সারি বদলে দেয়:
| AI-এর ভুল | ফল | আপনি যা করবেন |
|---|---|---|
| UPDATE বা DELETE-এ WHERE অসম্পূর্ণ বা নেই | পুরো টেবিল বদলে বা মুছে যায় | আগে একই WHERE দিয়ে SELECT; transaction-এর ভেতরে চালান |
| JOIN-এর শর্ত ভুল বা অসম্পূর্ণ | সারি দুই-তিনগুণ, যোগফল ফুলে ওঠে | JOIN-এর আগে-পরে COUNT(*) মিলিয়ে দেখুন |
= NULL লেখে, বা NULL ভুলে যায় | কিছু সারি নীরবে বাদ পড়ে | নমুনা ডেটায় একটি NULL রেখে পরীক্ষা করুন |
| অন্য dialect-এর কমান্ড (MySQL-এ TOP) | ত্রুটি, বা ভিন্ন আচরণ | প্রশ্নে ডেটাবেসের নাম আর version বলুন |
| ব্যবহারকারীর ইনপুট জোড়া দিয়ে SQL বানায় | SQL injection-এর দরজা খোলা | parameterized query চান; জোড়া দেওয়া কোড ফেরত দিন |
ভালো প্রশ্নে থাকে: ডেটাবেসের নাম, টেবিলের কাঠামো (আসল গোপন ডেটা নয়), কী চান, আর যাচাইয়ের অনুরোধ:
AI-এর SQL চালানোর আগে — চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। পঞ্চাশ বছর পুরোনো একটি ভাষা কেন আজও ডেটার জগৎ শাসন করে, তার গল্প এখানে।
প্র ০১SQL কোথা থেকে এলো? IBM-এর SEQUEL থেকে ANSI মান পর্যন্ত গল্পটা কী?
১৯৭০ সালে IBM-এর গবেষক Edgar F. Codd একটি গবেষণাপত্রে রিলেশনাল মডেলের প্রস্তাব দেন — ডেটা থাকবে গাণিতিক “relation” বা টেবিলে, আর প্রশ্ন করা হবে যুক্তি দিয়ে, ডেটা কোথায় কীভাবে রাখা আছে তা না জেনেই। তখনকার ডেটাবেসে প্রোগ্রামারকে রেকর্ড থেকে রেকর্ডে পয়েন্টার ধরে “হেঁটে” যেতে হতো। Codd-এর ধারণা ছিল বিপ্লবী, কিন্তু তাঁর গাণিতিক ভাষা সাধারণ মানুষের পক্ষে লেখা কঠিন ছিল।
IBM-এর আরও দুই গবেষক, Donald Chamberlin আর Raymond Boyce, এমন একটি ভাষা বানাতে চাইলেন যা ইংরেজি বাক্যের মতো পড়া যায়। ১৯৭৪ সালে তাঁরা প্রকাশ করেন SEQUEL — Structured English Query Language. পরে যুক্তরাজ্যের একটি কোম্পানির ট্রেডমার্কের সাথে নামের মিল থাকায় নাম ছোট হয়ে দাঁড়ায় SQL — যদিও “সিকুয়েল” উচ্চারণ আজও টিকে আছে। IBM-এর পরীক্ষামূলক প্রকল্প System R-এ ভাষাটি পরীক্ষা করা হয়।
মজার ব্যাপার, প্রথম বাণিজ্যিক SQL ডেটাবেস IBM আনেনি। IBM-এর প্রকাশিত গবেষণা পড়ে Larry Ellison-এর ছোট একটি কোম্পানি ১৯৭৯ সালে বাজারে আনে Oracle — কোম্পানিটি পরে নিজেই এই নামে পরিচিত হয়। IBM-এর নিজের পণ্য (SQL/DS, পরে DB2) আসে কয়েক বছর পরে।
অনেক কোম্পানি নিজের মতো SQL বানাতে থাকায় একটি সাধারণ মানের দরকার হয়। ১৯৮৬ সালে আমেরিকার মান-সংস্থা ANSI SQL-কে আনুষ্ঠানিক মান হিসেবে গ্রহণ করে, পরের বছর আন্তর্জাতিক সংস্থা ISO-ও। এরপর SQL-92, SQL:1999 থেকে শুরু করে ২০২৩ সালের সংস্করণ পর্যন্ত মানটি বারবার হালনাগাদ হয়েছে — JSON, সময়-ভিত্তিক ডেটা, গ্রাফ-প্রশ্ন যুক্ত হয়েছে। কিন্তু ১৯৭০-এর দশকের SELECT … FROM … WHERE আজও হুবহু একই।
মূল উপলব্ধি: একটি ভাষা টিকে থাকে যখন তা একটি শক্ত গাণিতিক ভিত্তির ওপর দাঁড়িয়ে সাধারণ মানুষের পড়ার মতো সহজ হয়, আর একটি খোলা মান সবাইকে একই ভাষায় কথা বলতে দেয়।
প্র ০২“কী চাই” বলা আর “কীভাবে করব” বলার পার্থক্য কেন এত গুরুত্বপূর্ণ? declarative SQL কেন optimizer-কে পথ বাছতে দেয়?
C বা Python-এর মতো imperative ভাষায় আপনি ধাপগুলো লেখেন: এই লুপ, এই শর্ত, এই তালিকা। কম্পিউটার ঠিক সেভাবেই করে — আপনার পদ্ধতি ধীর হলে প্রোগ্রামও ধীর। SQL declarative: আপনি শুধু ফলাফলের বৈশিষ্ট্য বলেন। কীভাবে সেটা পাওয়া যাবে, সেই সিদ্ধান্ত ডেটাবেসের হাতে।
এই স্বাধীনতা কেন মূল্যবান? একটি সাধারণ JOIN-ও অনেক উপায়ে করা যায় — কোন টেবিল আগে পড়া হবে, index ব্যবহার হবে কি না, সারিগুলো মেলানো হবে লুপ করে, সাজিয়ে, না hash টেবিল বানিয়ে। পাঁচটি টেবিলের JOIN-এ সম্ভাব্য ক্রম শতাধিক। ১৯৭৯ সালে IBM-এর System R দলের Patricia Selinger ও সহকর্মীরা একটি পদ্ধতি প্রকাশ করেন, যেখানে ডেটাবেস প্রতিটি সম্ভাব্য পথের আনুমানিক খরচ (কতবার ডিস্ক পড়তে হবে) হিসাব করে সবচেয়ে সস্তাটি বেছে নেয়। এই cost-based optimizer-এর ধারণা আজও প্রায় সব বড় ডেটাবেসের ভিত্তি।
এর বড় সুবিধা: ডেটা বদলালে পরিকল্পনাও বদলায়, আপনার প্রশ্ন না বদলেই। আজ টেবিলে ১০০ সারি থাকলে পুরো টেবিল পড়াই দ্রুত; কাল ১ কোটি সারি হলে এবং কেউ একটি index যোগ করলে, একই SQL নিজে থেকেই index ব্যবহার শুরু করবে। ডেটাবেস নির্মাতারা নতুন কৌশল যোগ করলে পুরোনো প্রশ্নগুলোও দ্রুত হয়ে যায়। বেশিরভাগ ডেটাবেসে EXPLAIN লিখে দেখা যায় optimizer কোন পথ বেছেছে।
তবে স্বাধীনতার দামও আছে। optimizer-এর অনুমান ভুল হলে একটি প্রশ্ন হঠাৎ ধীর হয়ে যেতে পারে, আর কেন — তা বোঝা কঠিন। এজন্য বড় প্রতিষ্ঠানে “ডেটাবেস পারফরম্যান্স” আলাদা একটি দক্ষতা। HTML আর Excel-এর সূত্রও আংশিকভাবে declarative — আপনি বলেন কী দেখাতে হবে, ব্রাউজার বা Excel ঠিক করে কীভাবে।
মূল উপলব্ধি: “কী” আর “কীভাবে” আলাদা করলে প্রতিটি অংশ আলাদাভাবে উন্নত হতে পারে। ভালো বিমূর্ততা (পর্ব ২৩) ব্যবহারকারীকে সরল ভাষা দেয়, আর ভেতরের যন্ত্রকে বুদ্ধিমান হওয়ার সুযোগ।
প্র ০৩SQL injection এত পুরোনো আর সহজে ঠেকানো যায় — তবু কেন বছরের পর বছর বড় বড় তথ্য ফাঁসের কারণ হয়েছে? “Bobby Tables” কৌতুকটি কী শেখায়?
SQL injection প্রথম প্রকাশ্যে বিস্তারিতভাবে বর্ণিত হয় ১৯৯৮ সালের ডিসেম্বরে, Phrack নামের একটি নিরাপত্তা-পত্রিকায় Jeff Forristal-এর লেখায়। তখন ওয়েবসাইটগুলো সবে ডেটাবেসের সাথে যুক্ত হচ্ছে, আর বেশিরভাগ প্রোগ্রামার ব্যবহারকারীর ইনপুট সরাসরি SQL-এর লেখার সাথে জুড়ে দিতেন — কারণ সেটাই সবচেয়ে সহজ মনে হতো।
মূল সমস্যাটা হলো কোড আর ডেটা এক স্রোতে মিশে যাওয়া. ডেটাবেস একটি লেখা পায় এবং পুরোটাকেই কমান্ড হিসেবে পড়ে। ইনপুটের ভেতরে কোনো উদ্ধৃতিচিহ্ন বা SQL-এর মতো অংশ থাকলে সেটা কমান্ডের কাঠামো বদলে দিতে পারে। ২০০০-এর দশকে এর মাধ্যমে বেশ কয়েকটি বড় ঘটনা ঘটে — ২০০৮ সালের Heartland Payment Systems-এর ঘটনায় দশ কোটির বেশি পেমেন্ট কার্ডের তথ্য চুরি যায়, আর ২০১৫ সালে যুক্তরাজ্যের টেলিকম কোম্পানি TalkTalk-এর লক্ষাধিক গ্রাহকের তথ্য ফাঁস হয়। ওয়েব নিরাপত্তার সংগঠন OWASP-এর বহুল ব্যবহৃত “Top 10” ঝুঁকির তালিকায় injection ২০১০, ২০১৩ আর ২০১৭ সালে এক নম্বরে ছিল; ২০২১-এর তালিকায় তিন নম্বরে নেমেছে, পরে আরও কিছুটা নিচে — কমেছে, কিন্তু হারায়নি।
২০০৭ সালে Randall Munroe-র জনপ্রিয় ওয়েব কমিক xkcd-এর ৩২৭ নম্বর পর্বে (“Exploits of a Mom”) একটি স্কুল এক মায়ের কাছে ফোন করে জানায়, তাদের ছাত্রদের সব রেকর্ড হারিয়ে গেছে। কারণ, মা ছেলের নাম এমনভাবে রেখেছিলেন যে নামটির একটি অংশ SQL কমান্ড হিসেবে পড়লে Students টেবিল মুছে দেয়। ছেলের ডাকনাম তাই “Little Bobby Tables”. শেষে মায়ের পরামর্শ — “আশা করি এবার থেকে আপনারা ডেটাবেসের ইনপুট ঠিকমতো sanitize করবেন।” কৌতুকটি এত জনপ্রিয় যে নিরাপত্তা-প্রশিক্ষণে আজও দেখানো হয়।
তবু ভুলটা টিকে আছে কেন? পুরোনো কোড যা কেউ আর হাত দেয় না; নতুনদের টিউটোরিয়াল, যেখানে সহজতার জন্য জোড়া দেওয়া SQL দেখানো হয়; আর এখন AI-এর লেখা কোড, যা পুরোনো উদাহরণ থেকে শেখা। আধুনিক লাইব্রেরি parameterized query-কে সবচেয়ে সহজ পথ বানিয়েছে, তাই নতুন কোডে এটি কমছে।
মূল উপলব্ধি: নিরাপত্তার সবচেয়ে ভালো সমাধান হলো নিরাপদ পথটিকেই সবচেয়ে সহজ পথ বানানো। আর মৌলিক নিয়ম — কোড আর ডেটা সবসময় আলাদা চ্যানেলে।
প্র ০৪NULL কেন এত ঝামেলার? Tony Hoare-এর “billion-dollar mistake” আর SQL-এর তিন-মানের যুক্তি কী?
ব্রিটিশ কম্পিউটার বিজ্ঞানী Tony Hoare (Quicksort অ্যালগরিদমের উদ্ভাবক) ১৯৬৫ সালে ALGOL W নামের প্রোগ্রামিং ভাষায় “null reference” যোগ করেন — এমন একটি পয়েন্টার, যা কিছুই নির্দেশ করে না। ২০০৯ সালে লন্ডনের একটি সম্মেলনে (QCon) তিনি একে বলেন তাঁর “billion-dollar mistake”: গত কয়েক দশকে null-এর কারণে যত প্রোগ্রাম ক্র্যাশ, ত্রুটি আর নিরাপত্তা-সমস্যা হয়েছে, তার ক্ষতি সম্ভবত শত কোটি ডলার। প্রোগ্রামিং ভাষার null আর SQL-এর NULL হুবহু এক জিনিস নয়, কিন্তু দুটিই একই প্রশ্ন তোলে: “মান নেই” অবস্থাটাকে কীভাবে সামলাব?
SQL-এ NULL মানে “অজানা”. Codd-এর রিলেশনাল মডেল এর সাথে তিন-মানের যুক্তি (three-valued logic) এনেছে: সত্য, মিথ্যা, আর UNKNOWN. Mitu-র GPA অজানা — তাহলে “Mitu-র GPA = ৫?” এর উত্তর হ্যাঁ বা না নয়, “জানি না”. এমনকি NULL = NULL-ও UNKNOWN — দুটি অজানা মান সমান কি না, তা-ও অজানা। WHERE শুধু সত্য সারি রাখে, UNKNOWN বাদ দেয়। এজন্য WHERE gpa = NULL কিছুই দেয় না।
পর্ব ১৯-এর বুলিয়ান সত্য-সারণি এখানে বড় হয়: UNKNOWN AND FALSE = FALSE (একটি মিথ্যা থাকলেই পুরোটা মিথ্যা), কিন্তু UNKNOWN AND TRUE = UNKNOWN. UNKNOWN OR TRUE = TRUE. সবচেয়ে কুখ্যাত ফাঁদ: WHERE roll NOT IN (101, NULL) কোনো সারিই দেয় না, কারণ প্রতিটি সারির জন্য “roll ≠ NULL” অজানা থেকে যায়। আবার AVG, COUNT(gpa) NULL বাদ দিয়ে হিসাব করে — কখনো সেটাই চাওয়া, কখনো বিভ্রান্তিকর।
ডেটাবেস তাত্ত্বিক Chris Date বহু বছর ধরে যুক্তি দিয়েছেন যে NULL রিলেশনাল মডেলকেই দুর্বল করে; Codd নিজে পরে দুই ধরনের অনুপস্থিত মানের (“প্রযোজ্য কিন্তু অজানা” আর “প্রযোজ্যই নয়”) প্রস্তাব দেন। আধুনিক প্রোগ্রামিং ভাষাগুলো (Rust, Kotlin, Swift) null-কে টাইপ ব্যবস্থার ভেতরে স্পষ্ট করে নিয়ন্ত্রণ করে। ব্যবহারিক পরামর্শ: যে কলামে মান থাকা বাধ্যতামূলক, সেখানে NOT NULL দিন, আর NULL থাকতে পারে এমন কলামে প্রতিটি শর্ত NULL দিয়ে পরীক্ষা করুন।
মূল উপলব্ধি: “জানি না” একটি বৈধ উত্তর — কিন্তু তা যুক্তির নিয়ম বদলে দেয়। যে সিস্টেম অজানাকে স্পষ্টভাবে সামলায়, সেটাই নির্ভরযোগ্য।
প্র ০৫২০১০-এর দশকে “NoSQL” কেন জনপ্রিয় হলো, আর পরে SQL কীভাবে আবার ফিরে এলো?
২০০০-এর দশকে Google, Amazon, Facebook-এর মতো প্রতিষ্ঠানের ডেটা এমন আকারে পৌঁছায়, যা একটি বড় সার্ভারে আঁটে না — হাজার হাজার সাধারণ কম্পিউটারে ছড়িয়ে রাখতে হয়। প্রচলিত রিলেশনাল ডেটাবেস তখন মূলত একটি যন্ত্রে চলার জন্য তৈরি ছিল। Google ২০০৬ সালে Bigtable আর Amazon ২০০৭ সালে Dynamo নামের নিজস্ব ব্যবস্থার গবেষণাপত্র প্রকাশ করে, যেখানে কঠোর টেবিল-কাঠামো, JOIN আর পূর্ণ transaction-এর কিছু অংশ ছেড়ে দিয়ে বিপুল মাপে ছড়ানোর ক্ষমতা পাওয়া গিয়েছিল।
২০০৯ সালে সান ফ্রান্সিসকোর একটি মিটআপকে কেন্দ্র করে এই ধরনের ডেটাবেসের জন্য “NoSQL” নামটি জনপ্রিয় হয়। একই সময়ে আসে MongoDB (ডকুমেন্ট বা JSON-এর মতো রেকর্ড), Cassandra, Redis-এর মতো ব্যবস্থা। প্রতিশ্রুতি ছিল — schema নিয়ে মাথাব্যথা নেই, যত খুশি সার্ভার যোগ করুন। কিছু বছর মনে হচ্ছিল SQL পুরোনো হয়ে যাচ্ছে।
কিন্তু বাস্তবে বেশ কিছু সমস্যা দেখা দেয়। transaction না থাকলে টাকা-পয়সার হিসাবে অসঙ্গতি ঠেকানোর দায় পড়ে প্রোগ্রামারের ঘাড়ে। schema না থাকলেও ডেটার কাঠামো তো থাকেই — শুধু তা লুকিয়ে থাকে কোডের ভেতরে। আর বিশ্লেষক, ব্যবসায়ী, ডেটা সায়েন্টিস্ট — সবাই SQL জানেন, প্রতিটি NoSQL ব্যবস্থার আলাদা প্রশ্ন-ভাষা শিখতে চান না। ফলে উল্টো স্রোত শুরু হয়: Cassandra আনে SQL-এর মতো দেখতে CQL; বড় ডেটার Hadoop-এর ওপর আসে Hive-এর মতো SQL স্তর; Google ২০১২ সালে Spanner প্রকাশ করে — সারা পৃথিবীতে ছড়ানো, অথচ transaction আর SQL-সহ। “NewSQL” নামে নতুন ধারার ডেটাবেস দুই জগতের সুবিধা একসাথে দিতে চায়। আবার PostgreSQL-এর মতো রিলেশনাল ডেটাবেস JSON রাখার ক্ষমতা যোগ করে NoSQL-এর সুবিধার একটি বড় অংশ নিজেই দিয়ে দেয়।
আজকের চিত্র মিশ্র: ক্যাশের জন্য Redis, নির্দিষ্ট কাজে ডকুমেন্ট বা গ্রাফ ডেটাবেস — আর বেশিরভাগ ব্যবসার মূল ডেটা এখনো রিলেশনাল, SQL দিয়ে। ডেটা বিশ্লেষণের বড় বড় ক্লাউড প্ল্যাটফর্মও SQL-কেই প্রধান ভাষা রেখেছে।
মূল উপলব্ধি: প্রযুক্তির ঢেউ আসে-যায়, কিন্তু একটি ভালো বিমূর্ততা আর একটি বহুল প্রচলিত ভাষা খুব কঠিনে মরে। নতুন টুল বাছার আগে জিজ্ঞেস করুন — আমি কোন নিশ্চয়তা ছেড়ে দিচ্ছি, আর বিনিময়ে কী পাচ্ছি?
অনুশীলন
প্রথম তিনটি খাতা-কলমে করা যায়; আমাদের স্কুলের ডেটাবেস (students আর results) ধরে নিন। চাইলে ওপরের চালানোর মতো ব্লকে SQL বসিয়ে মিলিয়ে নিন।
-
প্রশ্নকে SQL-এ রূপ দিন: (ক) ঢাকা বা খুলনার ছাত্রদের নাম আর GPA, GPA বড় থেকে ছোট। (খ) যাদের নামে “a” অক্ষর দ্বিতীয় স্থানে। (গ) প্রতিটি ছাত্রের তিন বিষয়ের মোট নম্বর, মোট ২৪০-এর বেশি হলে শুধু তারা। প্রতিটির প্রত্যাশিত ফলও লিখুন।
(ক)
SELECT name, gpa FROM students WHERE district IN ('Dhaka', 'Khulna') ORDER BY gpa DESC;— Fatema 5.00, Sadia 5.00, Karim 4.50, আর Mitu (NULL). SQLite-এ DESC সাজালে NULL শেষে আসে। Fatema আর Sadia-র ক্রম নিশ্চিত করতে, nameযোগ করুন। (খ)WHERE name LIKE '_a%'— Rahim, Karim, Fatema, Tanvir, Sadia. (গ)SELECT roll, SUM(marks) AS total FROM results GROUP BY roll HAVING SUM(marks) > 240 ORDER BY total DESC;— মোট দাঁড়ায় 104 (257), 101 (255), 103 (251), 106 (247); 102 (223) আর 105 (173) বাদ। এখানে WHERE চলবে না, কারণ শর্তটি যোগফলের ওপর — দলের ওপর। -
NULL-এর ধাঁধা: students টেবিলে নিচের প্রতিটি প্রশ্ন কয়টি সারি দেবে, আগে অনুমান করুন: (ক)
WHERE gpa = NULL(খ)WHERE gpa IS NULL(গ)WHERE gpa < 5(ঘ)WHERE NOT gpa < 5. (গ) আর (ঘ) মিলে কি আট হয়?(ক) ০ — NULL-এর সাথে
=সবসময় UNKNOWN. (খ) ১ — Mitu. (গ) ৪ — Karim, Nusrat, Tanvir, Arif. (ঘ) ৩ — Rahim, Fatema, Sadia. মোট ৭, আট নয়! Mitu দুটিতেই বাদ, কারণNULL < 5UNKNOWN, আরNOT UNKNOWN-ও UNKNOWN. সাধারণ যুক্তিতে “শর্ত বা তার বিপরীত — একটা তো সত্য হবেই”, কিন্তু তিন-মানের যুক্তিতে নয়। রিপোর্টে সারির সংখ্যা না মিললে প্রথমেই NULL খুঁজুন। -
কোন কমান্ড? প্রতিটি পরিস্থিতিতে কোন SQL কমান্ড, আর সেটা DDL না DML — (ক) নতুন শিক্ষাবর্ষে results-এর সব পুরোনো নম্বর মুছতে হবে, টেবিল থাকবে। (খ) subjects টেবিলটি আর লাগবে না। (গ) students-এ ইমেইলের কলাম যোগ। (ঘ) একজনের জেলা ভুল লেখা হয়েছে।
(ক)
DELETE FROM results;— DML; এখানে WHERE ছাড়া ইচ্ছাকৃত, তবু আগে backup আর transaction. কিছু ডেটাবেসেTRUNCATE TABLE results;দ্রুততর। (খ)DROP TABLE subjects;— DDL; তবে results-এর foreign key যদি subjects-কে নির্দেশ করে, ডেটাবেস আপত্তি করতে পারে — আগে সেই সম্পর্ক মীমাংসা করতে হবে। (গ)ALTER TABLE students ADD COLUMN email VARCHAR(100);— DDL. (ঘ)UPDATE students SET district = 'Bogura' WHERE roll = 107;— DML; WHERE-এ primary key, তাই ঠিক একটি সারি। -
হাতে-কলমে, DB Browser for SQLite-এ: একটি নতুন ডেটাবেস ফাইল বানিয়ে students টেবিল তৈরি করুন (CHECK-সহ), পাঁচটি সারি ঢোকান। তারপর (ক) gpa 6 দিয়ে একটি সারি ঢোকানোর চেষ্টা করুন, (খ) একই roll দুবার ঢোকান, (গ) WHERE ছাড়া একটি UPDATE চালান, Browse Data ট্যাবে ফল দেখুন, তারপর ওপরের “Revert Changes” বোতাম চাপুন। প্রতিবার কী বার্তা এলো লিখে রাখুন।
(ক) “CHECK constraint failed” ধরনের ত্রুটি — সারি ঢোকে না। (খ) “UNIQUE constraint failed: students.roll” — primary key-র দুবার হওয়া চলবে না। (গ) UPDATE পাঁচটি সারিই বদলায় (“5 rows affected”), টেবিল দেখলে সবার মান একই; “Revert Changes”-এর পরে আবার দেখুন — সব আগের মতো। কারণ DB Browser বদলগুলো একটি খোলা transaction-এ রাখে, “Write Changes” (COMMIT) না চাপা পর্যন্ত স্থায়ী করে না; Revert মানে ROLLBACK. ত্রুটির বার্তাগুলো শত্রু নয়: এগুলোই প্রমাণ যে constraint আপনার ডেটা পাহারা দিচ্ছে।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি SQL SELECT প্রশ্ন ডেটাবেস যে যৌক্তিক ক্রমে প্রক্রিয়া করে, অংশগুলো সেই ক্রমে সাজান (▲▼ চেপে সরান)
- 📂 FROM — কোন টেবিল (আর JOIN)
- 🔍 WHERE — সারি ছাঁকা
- 🧺 GROUP BY — দলে ভাগ
- 🧮 HAVING — দল ছাঁকা
- 📋 SELECT — কলাম বাছাই আর হিসাব
- ↕️ ORDER BY — সাজানো
নিচের কোনগুলো সবই DDL (Data Definition Language)-এর কমান্ড?
- INSERT, UPDATE, DELETE
- CREATE, ALTER, DROP
- SELECT, GRANT, REVOKE
- COMMIT, ROLLBACK, UPDATE
SQL-এ ORDER BY marks লিখলে, ASC বা DESC কিছু না দিলে, ফলাফল কোন ক্রমে সাজানো হয়?
- যে ক্রমে ডেটা ঢোকানো হয়েছিল
- বড় থেকে ছোট
- ছোট থেকে বড়
- ত্রুটি দেখাবে, কারণ ক্রম বলা বাধ্যতামূলক
একটি টেবিলের সব সারি মুছে ফেলতে হবে, কিন্তু টেবিলের কাঠামো (কলামগুলো) রেখে দিতে হবে। কোন কমান্ড উপযুক্ত?
DROP TABLE results;ALTER TABLE results;SELECT * FROM results;DELETE FROM results;
“নামের শেষ অক্ষর a” — এমন সব ছাত্র খুঁজতে কোন শর্তটি সঠিক?
WHERE name LIKE '%a'WHERE name LIKE 'a%'WHERE name LIKE '_a'WHERE name = '%a'
results টেবিলে প্রতিটি বিষয়ের গড় নম্বর বের করে শুধু যেসব বিষয়ের গড় ৭৫-এর বেশি, সেগুলো দেখাতে হবে। কোন প্রশ্নটি সঠিক?
SELECT subject, AVG(marks) FROM results WHERE AVG(marks) > 75 GROUP BY subject;SELECT subject, AVG(marks) FROM results GROUP BY subject HAVING AVG(marks) > 75;SELECT subject, AVG(marks) FROM results WHERE marks > 75 GROUP BY subject;SELECT subject, AVG(marks) FROM results HAVING marks > 75;
একটি ওয়েবসাইটে ব্যবহারকারী রোল নম্বর লিখে ফল দেখেন। SQL injection প্রতিরোধের সবচেয়ে নির্ভরযোগ্য উপায় কোনটি?
- টেবিলের নাম গোপন রাখা
- শুধু ব্রাউজারে JavaScript দিয়ে ইনপুট যাচাই
- Parameterized query — মান
?চিহ্নের জায়গায় আলাদাভাবে পাঠানো - ইনপুটের চারপাশে উদ্ধৃতিচিহ্ন বসিয়ে SQL-এর সাথে জোড়া দেওয়া
students (৮ জন) আর results (৬ জনের ফল) টেবিল roll দিয়ে জোড়া হলো। কোন JOIN ফলাফলে সব ৮ জন ছাত্রকেই রাখবে, যাদের ফল নেই তাদের marks-এ NULL বসিয়ে?
students LEFT JOIN resultsstudents INNER JOIN resultsstudents JOIN results- শর্ত ছাড়া দুই টেবিল জোড়া
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- SQL declarative — আপনি বলেন কী চান, ডেটাবেসের optimizer ঠিক করে কীভাবে। DDL (CREATE, ALTER, DROP), DML (INSERT, UPDATE, DELETE), DQL (SELECT), DCL (GRANT).
- টেবিল বানানোর সময় data type আর constraint (PRIMARY KEY, NOT NULL, UNIQUE, CHECK, DEFAULT, FOREIGN KEY) — ভুল ডেটা ঢোকার আগেই আটকায়।
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT; কাজের ক্রম শুরু হয় FROM থেকে। ORDER BY-এর ডিফল্ট ASC; NULL খুঁজতে IS NULL.- WHERE ছাঁকে সারি, HAVING ছাঁকে দল; INNER JOIN শুধু মিল পাওয়া সারি, LEFT JOIN বাঁয়ের সবাই।
- UPDATE/DELETE-এর আগে একই WHERE দিয়ে SELECT, ঝুঁকির কাজ transaction-এ; ব্যবহারকারীর মান সবসময় parameterized query-তে — আর AI-এর SQL নমুনা ডেটায় যাচাই করে তবেই।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৪৩ · সাইবার নিরাপত্তা — পাসওয়ার্ড, 2FA, phishing আর ম্যালওয়্যারপরবর্তী পর্বমডিউল ৭-এর শুরু — নিজের ডিজিটাল জীবন সুরক্ষিত রাখা।
- পর্ব ৪১ · ডেটাবেস — টেবিল, key, relation আর normalizationআগের পর্বSQL-এর নিচের ভিত্তি — টেবিল কীভাবে নকশা করতে হয়।
- কম্পিউটার ফান্ডামেন্টালস ও ICT · কোর্স হোম৫৫টি পর্বপুরো কোর্সের রোডম্যাপ — কোন পর্ব কখন।
- DBMS ও SQLগভীরে যানsubquery, ER ডায়াগ্রাম, normalization, index আর transaction — পূর্ণাঙ্গ কোর্স।
- Python দিয়ে SQLiteহাতে-কলমেপ্রোগ্রাম থেকে ডেটাবেস — connection, commit আর নিরাপদ query.