সরাসরি পর্বে যান
পর্ব ১২ · ৬৭-এর মধ্যে · মডিউল ৩

SQL পরিচিতি আর সেটআপ — SQLite, MySQL আর PostgreSQL

Introduction to SQL and Setup — Syntax Basics, Standards, SQLite, MySQL and PostgreSQL

Taught in Bangla, this lesson introduces SQL as a declarative language and its five sub-languages, the history of the standard from SEQUEL to SQL:2023, SQL grammar including keywords, identifiers, quoting, strings and comments, what happens inside the DBMS after a statement is sent, running SQL in the live editor, installing SQLite, PostgreSQL and MySQL, and reading error messages.

এই পর্বে যা শিখবেন

  • SQL কী, কেন declarative, আর এর পাঁচটি উপ-ভাষা
  • SEQUEL থেকে SQL:2023 — standard-এর ইতিহাস আর কোন সংস্করণে কী এসেছে
  • SQL-এর ব্যাকরণ: স্টেটমেন্ট, keyword, identifier, quoting, string, comment আর লেখার ধরন
  • একটি SQL স্টেটমেন্ট টাইপ করার পর DBMS-এর ভেতরে কোন পথে যায়
  • SQLite, PostgreSQL আর MySQL ইনস্টল করে প্রথম সেশন, আর error message পড়ে ভুল খুঁজে বের করা

১ · SQL কী — “কী চাই” বলার ভাষা

মডিউল ১ আর ২-এ আপনি শিখেছেন ডেটা কেন টেবিলে রাখা হয়, key কী, আর ER মডেল থেকে কীভাবে টেবিল বানানো হয়। এবার সেই টেবিলগুলোর সাথে কথা বলার পালা। কথা বলার ভাষাটির নাম SQL — Structured Query Language. প্রায় প্রতিটি relational database এই ভাষা বোঝে: ব্যাংকের হিসাবের সফটওয়্যার, বিশ্ববিদ্যালয়ের ফল প্রকাশের সিস্টেম, অনলাইন দোকান, এমনকি আপনার ফোনের কন্টাক্ট তালিকাও।

একটি বড় লাইব্রেরির কথা ভাবুন। আপনি কাউন্টারে গিয়ে বললেন, “২০২০ সালের পরে ছাপা, বাংলায় লেখা সব প্রোগ্রামিং বই দিন, নতুনগুলো আগে।” আপনি বলেননি কোন তাকে আগে যেতে হবে, কোন ক্যাটালগ খুলতে হবে। সেটি লাইব্রেরিয়ানের কাজ — তিনি জানেন কোন পথে সবচেয়ে দ্রুত হবে। SQL-এ আপনি ঠিক এভাবেই লেখেন: কী চাই. আর DBMS হলো সেই অভিজ্ঞ লাইব্রেরিয়ান, যে ঠিক করে কীভাবে আনবে।

এই ধরনের ভাষাকে বলে declarative. উল্টো দিকে আছে procedural ভাষা — C, Python বা Java — যেখানে আপনাকে প্রতিটি ধাপ বলে দিতে হয়: “প্রথম সারি নাও, দাম দেখো, ১০০০-এর কম হলে তালিকায় রাখো, পরের সারিতে যাও…”। নিচের এডিটরে একটি SQL প্রশ্ন আছে। এখানে কোনো loop নেই, কোনো “পরের সারিতে যাও” নেই — শুধু চাওয়াটুকু।

এই পর্বের বেশিরভাগ লাইভ SQL চলে দোকানের ডেটাবেসে (db-shop). এতে পাঁচটি টেবিল: customers (customer_id, name, city, phone, joined_on — ৮ জন গ্রাহক), categories (category_id, name — ৪টি পণ্য-শ্রেণি), products (product_id, name, category_id, price, stock — ১০টি পণ্য, দাম টাকায়), orders (order_id, customer_id, order_date, status — ১০টি অর্ডার) আর order_items (order_id, product_id, quantity, unit_price — কোন অর্ডারে কোন পণ্য কতটি)। প্রতিটি এডিটরের নিচে “নমুনা ডেটাবেস” বাক্সে পুরো টেবিলগুলো দেখা যায়।

-- কী চাই: ১০০০ টাকার কম দামের পণ্য, সস্তা থেকে দামি
SELECT name, price
FROM products
WHERE price < 1000
ORDER BY price;

ফলে ৪টি সারি: Mustard Oil 1L | 260, Rice 5kg | 420, SQL Book | 550 আর DSA Book | 650. আপনি বলেছেন কোন কলাম চাই (SELECT), কোন টেবিল থেকে (FROM), কোন শর্তে (WHERE) আর কোন ক্রমে (ORDER BY). ১০টি সারির কোনটি আগে পড়া হবে, কোনো index ব্যবহার হবে কি না, সাজানোর জন্য কোন অ্যালগরিদম — কিছুই বলেননি। এবার 1000 বদলে 2000 লিখে দেখুন — ফল নিজে থেকেই বদলে যাবে। SQL-এর প্রতিটি অংশ পর্ব ১৫ থেকে বিস্তারিত শিখবেন; এখানে শুধু ভাষাটির স্বাদ নিন।

SQL ভাষা, DBMS সফটওয়্যার

নতুনরা প্রায়ই গুলিয়ে ফেলেন: “আমি SQL ইনস্টল করেছি।” আসলে SQL ইনস্টল করা যায় না — SQL একটি ভাষা, যেমন বাংলা একটি ভাষা। যা ইনস্টল করেন, তা হলো একটি RDBMS সফটওয়্যার, যে এই ভাষা বোঝে: SQLite, PostgreSQL, MySQL, MariaDB, Oracle Database, Microsoft SQL Server. নামে “SQL” থাকলেও MySQL বা SQL Server ভাষার নাম নয়, পণ্যের নাম। প্রত্যেকে মূল SQL বোঝে, তবে প্রত্যেকের নিজস্ব কিছু শব্দ আর রীতি আছে — এগুলোকে বলে SQL dialect বা উপভাষা, যেমন ঢাকা আর চট্টগ্রামের বাংলা। উপভাষার পূর্ণ তুলনা পর্ব ৩১-এ।

উচ্চারণ নিয়ে: SQL-কে কেউ বলেন “এস-কিউ-এল”, কেউ “সিকুয়েল”। দুটিই চলে। আদি নাম ছিল SEQUEL (অংশ ৩), তাই “সিকুয়েল” এসেছে; standard-এর নথি আর অনেক বিশেষজ্ঞ অক্ষর ধরে “এস-কিউ-এল” বলেন। Microsoft-এর পণ্যকে সাধারণত “সিকুয়েল সার্ভার” বলা হয়, MySQL-এর নির্মাতারা নিজেরা বলেন “মাই-এস-কিউ-এল”, আর PostgreSQL-কে সংক্ষেপে “পোস্টগ্রেস”। ইন্টারভিউতে যেকোনোটি বললেই চলবে — কেউ নম্বর কাটবে না।

২ · এক ভাষার পাঁচ ভাগ — DDL, DML, DQL, DCL আর TCL

পর্ব ৩-এ দেখেছেন, DBMS-এর ভাষাকে কাজ অনুযায়ী কয়েক ভাগে ভাগ করা হয়। SQL-এ এই সব ভাগ একই ব্যাকরণে লেখা — আলাদা ভাষা শিখতে হয় না, শুধু আলাদা শব্দ। সংক্ষেপে আবার দেখে নিই, কারণ এই মডিউলের বাকি পর্বগুলো ঠিক এই ভাগ ধরে এগোবে:

ভাগকাজপ্রধান স্টেটমেন্টএই কোর্সে
DDL — Data Definitionটেবিল আর গঠন তৈরি ও বদলCREATE, ALTER, DROPপর্ব ১৩, ২৩
DML — Data Manipulationসারি ঢোকানো, বদলানো, মোছাINSERT, UPDATE, DELETEপর্ব ১৪
DQL — Data Queryডেটা পড়া, প্রশ্ন করাSELECTপর্ব ১৫–২২
DCL — Data Controlকে কী করতে পারবেGRANT, REVOKEপর্ব ৫১
TCL — Transaction Controlএকসাথে সফল বা একসাথে বাতিলBEGIN, COMMIT, ROLLBACKপর্ব ৪৪

অনেক বই SELECT-কে DML-এর মধ্যেই রাখে (কারণ standard-এ SELECT “data manipulation”-এর অংশ), আবার অনেকে আলাদা করে DQL বলে। পরীক্ষায় দুটি উত্তরই গ্রহণযোগ্য, শুধু যুক্তি দিয়ে লিখুন। বাস্তবে সবচেয়ে বেশি লেখা হয় SELECT — একটি সাধারণ অ্যাপে পড়ার কাজ লেখার কাজের চেয়ে বহুগুণ বেশি হয়।

৩ · ইতিহাস আর standard — SEQUEL থেকে SQL:2023

১৯৭০ সালে IBM-এর গবেষক Edgar F. Codd relational model প্রস্তাব করেন (পর্ব ৫)। কিন্তু তাঁর প্রস্তাবিত ভাষা ছিল গাণিতিক চিহ্নে ভরা — সাধারণ ব্যবহারকারীর জন্য কঠিন। IBM-এর San Jose গবেষণাগারে Donald Chamberlin আর Raymond Boyce ১৯৭৪ সালে প্রকাশ করেন “SEQUEL: A Structured English Query Language” — ইংরেজির মতো পড়া যায় এমন একটি ভাষা। IBM-এর পরীক্ষামূলক System R প্রকল্পে এটি বাস্তবায়িত হয়। পরে “SEQUEL” নামটির trademark অন্য একটি (ব্রিটিশ বিমান-প্রস্তুতকারক) কোম্পানির থাকায় নাম ছোট করে রাখা হয় SQL.

মজার ব্যাপার, প্রথম বাণিজ্যিক SQL ডেটাবেস IBM-এর নয়। ১৯৭৯ সালে Relational Software, Inc. (পরে Oracle Corporation) বাজারে আনে Oracle V2. IBM-এর SQL/DS আসে ১৯৮১-তে, DB2 ১৯৮৩-তে। একই সময়ে Berkeley-র Ingres প্রকল্পের QUEL ভাষাও প্রতিযোগী ছিল, কিন্তু IBM-এর প্রভাব আর পরে standard হওয়ায় SQL জিতে যায়।

নানা কোম্পানির SQL যাতে মোটামুটি এক থাকে, সেজন্য আমেরিকার ANSI ১৯৮৬ সালে আর আন্তর্জাতিক সংস্থা ISO ১৯৮৭ সালে SQL-কে standard হিসেবে গ্রহণ করে। তারপর থেকে কয়েক বছর পরপর নতুন সংস্করণ আসে। পরীক্ষা আর ইন্টারভিউর জন্য প্রধানগুলো মনে রাখুন:

সংস্করণযা নতুন এসেছে (প্রধান কয়েকটি)এই কোর্সে
SQL-86 (ANSI), ১৯৮৭ ISOপ্রথম standard — মূল SELECT, INSERT, UPDATE, DELETE, CREATE TABLE—
SQL-89Integrity: PRIMARY KEY, FOREIGN KEY, CHECKপর্ব ৬
SQL-92 (SQL2)বড় সংস্করণ: JOIN … ON লেখা, OUTER JOIN, CASE, CAST, তারিখ-সময়ের টাইপ, INTERSECT/EXCEPTপর্ব ১৬, ১৯, ২২
SQL:1999 (SQL3)Recursive query (WITH RECURSIVE), trigger, BOOLEAN, ROLLUP/CUBEপর্ব ২৫, ২৯
SQL:2003Window function (OVER), MERGE, identity কলাম, SQL/XMLপর্ব ২৬
SQL:2008FETCH FIRST n ROWS, TRUNCATEপর্ব ১৫
SQL:2011Temporal টেবিল — সারির ইতিহাস সময়সহ রাখাপর্ব ২৯ (সংক্ষেপে)
SQL:2016JSON ফাংশন, row pattern matchingপর্ব ৩০
SQL:2023JSON ডেটা টাইপ, property graph query (SQL/PGQ)পর্ব ৩০, ৫৯

একটি সতর্কতা: standard-এ কিছু আসা মানে সব DBMS-এ তা সেদিন থেকে আছে, এমন নয়। Window function standard-এ এসেছে ২০০৩-এ, কিন্তু MySQL-এ এসেছে ৮.০ সংস্করণে (২০১৮), আর SQLite-এ ৩.২৫ সংস্করণে (২০১৮)। আবার উল্টোটাও হয়: LIMIT কখনো standard-এ ছিল না, তবু SQLite, PostgreSQL আর MySQL তিনটিই এটি বোঝে। তাই কোনো feature ব্যবহারের আগে দেখে নিন আপনার DBMS আর তার সংস্করণ এটি সমর্থন করে কি না।

৪ · SQL-এর ব্যাকরণ — স্টেটমেন্ট, keyword, নাম আর লেখা

বাংলা বাক্যে যেমন শব্দ, যতিচিহ্ন আর দাঁড়ি থাকে, SQL-এর প্রতিটি statement-ও কয়েক রকম “শব্দ” বা token দিয়ে তৈরি। DBMS-এর প্রথম কাজ হলো আপনার লেখাকে এই token-এ ভাঙা — এই অংশকে বলে tokenizer. নিচের ডায়াগ্রামে একটি স্টেটমেন্ট token ধরে ধরে পড়ুন:

SELECT name , price FROM products WHERE price < 1000 ;
Tokenizer যা দেখছে
token-এর ধরন
অর্থ
  1. SELECT — keyword. Keyword হলো SQL-এর সংরক্ষিত শব্দ, যার অর্থ ভাষা নিজেই ঠিক করে দিয়েছে। SELECT বলে, “এটি একটি প্রশ্ন, ফলে কিছু সারি ফেরত চাই।”
  2. name , price — identifier আর কমা। Identifier হলো আপনার দেওয়া নাম — টেবিল, কলাম, view-এর নাম। কমা একটি punctuation, যা তালিকার জিনিসগুলো আলাদা করে। কমা বাদ পড়লে কী বিপদ হয়, অংশ ৮-এ দেখবেন।
  3. FROM — আরেকটি keyword. এটি বলে, এরপরে আসছে ডেটার উৎস। SQL-এর ক্রম নির্দিষ্ট: SELECT-এর তালিকা আগে, FROM পরে। উল্টো লিখলে syntax error.
  4. products — টেবিলের নাম। এটিও identifier. Tokenizer এখনো জানে না এমন টেবিল আছে কি না — সেটি পরে catalog দেখে যাচাই হয় (অংশ ৫)।
  5. WHERE — শর্তের শুরু। এরপর যা আসবে, তা প্রতিটি সারির জন্য সত্য বা মিথ্যা হবে; শুধু সত্য সারিগুলো ফলে আসবে।
  6. price < 1000 — identifier, operator, literal. < একটি তুলনার operator. 1000 একটি literal — কোডের ভেতরে সরাসরি লেখা একটি মান। সংখ্যা literal-এ quote লাগে না, লেখা (string) literal-এ লাগে।
  7. ; — স্টেটমেন্ট শেষ। সেমিকোলন বলে “এই স্টেটমেন্ট এখানে শেষ”। একসাথে কয়েকটি স্টেটমেন্ট পাঠালে DBMS এটি দেখেই আলাদা করে। Terminal-এ সেমিকোলন না দিলে DBMS আরও লেখার অপেক্ষায় বসে থাকে।

বড় হাতের, ছোট হাতের, ফাঁকা জায়গা

SQL-এর keyword case-insensitive: SELECT, select আর SeLeCt একই। ফাঁকা জায়গা, নতুন লাইন আর tab-ও (একসাথে whitespace) শুধু token আলাদা করে; একটি space আর দশটি space-এ কোনো পার্থক্য নেই। কিন্তু ডেটার মান আলাদা ব্যাপার। নিচে দেখুন:

/* একই প্রশ্ন, দুই রকম লেখা — ফল একই */
select name from categories where category_id=2;

SeLeCt   NAME
  FrOm   Categories     -- keyword আর নামে বড়-ছোট অক্ষর সমান
 WHERE   category_id = 2;

-- কিন্তু ডেটার মান? 'dhaka' আর 'Dhaka' কি এক?
SELECT COUNT(*) AS n FROM customers WHERE city = 'dhaka';
SELECT COUNT(*) AS n FROM customers WHERE city = 'Dhaka';

প্রথম দুটি স্টেটমেন্টের ফল হুবহু এক: Books. এলোমেলো অক্ষর আর অতিরিক্ত space-এ SQLite কিছু মনে করেনি; টেবিলের নাম Categories আর কলাম NAME-ও চিনেছে, কারণ SQLite-এ quote ছাড়া নামও case-insensitive. কিন্তু শেষ দুটির ফল আলাদা: 'dhaka'-তে n = 0, 'Dhaka'-তে n = 3. String-এর তুলনায় SQLite আর PostgreSQL বড়-ছোট অক্ষর আলাদা ধরে। সাবধান — MySQL-এর ডিফল্ট collation (তুলনার নিয়ম) case-insensitive, সেখানে দুটিতেই ৩ আসত। একই কোয়েরি দুই DBMS-এ দুই ফল — উপভাষার একটি ছোট নমুনা।

লেখা (string) আর নাম (identifier) — কোন quote কোথায়

SQL-এ দুই রকম quote-এর দুই কাজ, আর এটি নতুনদের সবচেয়ে সাধারণ ভুলগুলোর একটি:

  • Single quote '…' = string literal, অর্থাৎ ডেটার মান: 'Dhaka', '2025-10-01'. লেখার ভেতরে নিজেই একটি ' থাকলে পরপর দুটি লিখুন: 'Rahim''s Shop'.
  • Double quote "…" = quoted identifier, অর্থাৎ নাম। নামে space, বাংলা অক্ষর বা keyword থাকলে লাগে: "unit price", "order".
-- string literal: single quote; ভেতরের ' লিখতে দুটি ''
SELECT 'Rahim''s Shop' AS shop, 'Dhaka' AS city;

-- নামে space বা বাংলা থাকলে: double quote
SELECT name AS "পণ্যের নাম", price AS "unit price"
FROM products WHERE category_id = 2;

-- SQLite MySQL-এর backtick আর SQL Server-এর [ ]-ও মেনে নেয়
SELECT `name`, [price] FROM products WHERE product_id = 101;

-- ফাঁদ: string-এ double quote! SQLite চালায়, PostgreSQL চালাবে না
SELECT name FROM customers WHERE city = "Dhaka";

প্রথমটিতে একটি সারি: Rahim's Shop | Dhaka — দুটি '' মিলে একটি ' হয়েছে। দ্বিতীয়টির কলামের মাথায় লেখা “পণ্যের নাম” আর “unit price”, সারি দুটি: DSA Book | 650, SQL Book | 550. তৃতীয়টি Mobile Phone | 15000 — SQLite অন্য DBMS-এর quoting-ও বোঝে, যাতে সেখান থেকে আনা কোড চলে। চতুর্থটি সবচেয়ে শিক্ষণীয়: ফল ৩টি সারি (Rahim Uddin, Sabbir Hasan, Mitu Rani). SQLite প্রথমে "Dhaka" নামে কলাম খোঁজে, না পেয়ে পুরোনো সামঞ্জস্যের খাতিরে এটিকে string ধরে নেয়। PostgreSQL-এ একই কোয়েরি দেয় ERROR: column "Dhaka" does not exist. অভ্যাস তাই একটিই: মান সবসময় single quote-এ।

বিভিন্ন DBMS-এ নাম quote করার নিয়ম আলাদা। নিচের ব্লকগুলো চালানো যায় না — শুধু তুলনার জন্য:

SELECT "unit price" FROM "order details";   -- standard: double quote
-- quote ছাড়া নাম PostgreSQL ছোট হাতের অক্ষরে বদলে নেয়:
-- Products, PRODUCTS, products — তিনটিই products
-- কিন্তু "Products" (quote সহ) আলাদা একটি নাম!
SELECT `unit price` FROM `order details`;   -- backtick
-- double quote এখানে ডিফল্টে string! (ANSI_QUOTES mode চালু করলে identifier)
SELECT 'It\'s fine';    -- MySQL ডিফল্টে backslash escape-ও মানে
SELECT 'It''s fine';    -- standard লেখা — সব DBMS-এ চলে
SELECT [unit price] FROM [order details];   -- বর্গবন্ধনী
SELECT TOP 3 name FROM products;           -- LIMIT-এর বদলে TOP

Comment — নিজের জন্য, সহকর্মীর জন্য

SQL-এ দুই রকম comment: -- থেকে লাইনের শেষ পর্যন্ত, আর /* … */ যা কয়েক লাইন জুড়ে থাকতে পারে। DBMS comment পুরো উপেক্ষা করে। MySQL-এ ---এর পরে অন্তত একটি space বা নতুন লাইন লাগে (--comment লিখলে comment হয় না), আর সেখানে # দিয়েও comment লেখা যায়। নিরাপদ অভ্যাস: -- (পরে একটি space) লিখুন। ভালো comment বলে কেন — “বাতিল অর্ডার বাদ, কারণ হিসাব বিভাগ চায় না” — কী নয়, কারণ কী তা কোডেই লেখা।

আরও গভীরে: DBMS-এর parser সাধারণত হাতে লেখা হয় না, একটি parser generator ব্যাকরণের নিয়ম থেকে তৈরি করে। PostgreSQL-এর ব্যাকরণ Bison-এর জন্য লেখা একটি বড় ফাইল (gram.y), MySQL-ও Bison ব্যবহার করে, আর SQLite ব্যবহার করে নিজের তৈরি Lemon parser generator. এ কারণেই ব্যাকরণ ভুলের বার্তা প্রায়ই অস্পষ্ট — parser শুধু জানে “এই token-এ এসে আর কোনো নিয়ম মিলছে না”, কিন্তু আপনি আসলে কী লিখতে চেয়েছিলেন, তা জানে না। SQLite-এর double-quote-কে string ধরার আচরণটি তার নিজের ডকুমেন্টেশনেই একটি “misfeature” হিসেবে স্বীকৃত, আর compile-এর সময় তা বন্ধ করার উপায়ও আছে।

৫ · একটি স্টেটমেন্টের যাত্রা — Enter চাপার পর কী ঘটে

পর্ব ৩-এ DBMS-এর যন্ত্রাংশগুলোর নাম জেনেছেন। এবার একটি নির্দিষ্ট স্টেটমেন্ট ধরে সেই পথটি হেঁটে দেখি — কারণ error message বুঝতে হলে জানতে হবে সেটি কোন ধাপ থেকে এসেছে:

  1. Clientpsql / অ্যাপআপনি লেখেন
  2. Server / libraryport 5432পৌঁছে দেওয়া
  3. Parserparse treeব্যাকরণ আর নাম
  4. Optimizerquery planসেরা পথ বাছাই
  5. Executorrowsআসল কাজ
  6. Result৪টি সারিআপনার পর্দায়
আপনার লেখাএখনো শুধু অক্ষরের সারি
SELECT name, price
FROM products
WHERE price < 1000
ORDER BY price;
লেখাটি পৌঁছায়DBMS-এর ধরন অনুযায়ী
PostgreSQL : psql ──TCP──▶ localhost:5432 ──▶ server process
MySQL      : mysql ─TCP──▶ localhost:3306 ──▶ mysqld
SQLite     : কোনো নেটওয়ার্ক নেই — একই প্রোগ্রামের ভেতরে
             sqlite3_prepare() ফাংশন ডাকা হয়
Parse treeব্যাকরণ ঠিক? নামগুলো আছে?
SELECT
 ├─ কলাম   : name, price
 ├─ FROM   : products
 ├─ WHERE  : price < 1000
 └─ ORDER BY: price

catalog যাচাই: products টেবিল ✓  name ✓  price ✓
EXPLAIN QUERY PLAN (SQLite)optimizer-এর সিদ্ধান্ত
QUERY PLAN
 ├─ SCAN products
 └─ USE TEMP B-TREE FOR ORDER BY

price-এ index নেই → পুরো টেবিল পড়তে হবে,
তারপর আলাদা করে সাজাতে হবে
Executorপ্রতিটি সারিতে শর্ত যাচাই
101 Mobile Phone   15000  ✗
102 Headphone       1200  ✗
103 Power Bank      1800  ✗
104 DSA Book         650  ✓
105 SQL Book         550  ✓
106 Panjabi         2200  ✗
107 Saree           4500  ✗
108 Rice 5kg         420  ✓
109 Mustard Oil 1L   260  ✓
110 Smart Watch     3500  ✗
→ ৪টি সারি, এবার দাম অনুযায়ী সাজানো
Result setclient-এ ফেরত
name            price
──────────────  ─────
Mustard Oil 1L    260
Rice 5kg          420
SQL Book          550
DSA Book          650
  1. Client — আপনি লেখেন। Terminal-এর psql, mysql বা sqlite3, একটি GUI টুল, কিংবা আপনার অ্যাপের কোড — যে প্রোগ্রাম SQL পাঠায়, সে-ই client. এই মুহূর্তে লেখাটি কেবল কিছু অক্ষর; এর অর্থ কেউ এখনো যাচাই করেনি।
  2. পৌঁছে দেওয়া। PostgreSQL আর MySQL client-server DBMS: লেখাটি নেটওয়ার্ক দিয়ে একটি আলাদা server প্রোগ্রামে যায় (ডিফল্ট port PostgreSQL-এ 5432, MySQL-এ 3306), নিজের কম্পিউটারে হলেও। SQLite একটি embedded database — আলাদা server নেই, আপনার প্রোগ্রামের ভেতরেই একটি library হিসেবে চলে।
  3. Parser — ব্যাকরণ আর নাম। Parser token-গুলো থেকে একটি parse tree বানায়। ব্যাকরণ ভুল হলে এখানেই থামে: syntax error. তারপর system catalog দেখে যাচাই করে, টেবিল আর কলামগুলো সত্যিই আছে কি না — না থাকলে no such table বা no such column.
  4. Optimizer — পথ বাছাই। একই ফল পাওয়ার অনেক পথ থাকতে পারে। Optimizer সেগুলোর আনুমানিক খরচ হিসাব করে একটি query plan বেছে নেয়। এখানে price-এ কোনো index নেই, তাই plan: পুরো টেবিল পড়া (SCAN), তারপর একটি অস্থায়ী B-tree-তে সাজানো। আপনি এই সিদ্ধান্ত দেখতে পারেন EXPLAIN দিয়ে (পর্ব ৪১, ৪৩)।
  5. Executor — আসল কাজ। Executor plan মেনে storage থেকে page পড়ে, প্রতিটি সারিতে price < 1000 যাচাই করে। ১০টির মধ্যে ৪টি পাস করে: 104, 105, 108, 109. তারপর সেগুলোকে দাম অনুযায়ী সাজায়।
  6. Result — আপনার পর্দায়। ফলের সারিগুলোকে বলে result set. Client সেগুলো টেবিল আকারে দেখায়: 260, 420, 550, 650. বড় ফল হলে সারিগুলো একবারে নয়, ধাপে ধাপে আসে — তাই কোটি সারির টেবিলেও প্রথম সারি দ্রুত দেখা যেতে পারে।

এই ছবিটি মনে রাখুন। error message পড়ার সময় প্রথম প্রশ্ন হবে: ভুলটা কোন ধাপের? ব্যাকরণের (parser), নামের (catalog যাচাই), নাকি চলার সময়ের (executor — যেমন constraint ভাঙা, শূন্য দিয়ে ভাগ)? আর সবচেয়ে কঠিন ভুল সেটি, যা কোনো ধাপেই ধরা পড়ে না — কোয়েরি চলে, কিন্তু উত্তর ভুল।

৬ · SQL চালানোর প্রথম জায়গা — এই পাতার লাইভ এডিটর

এই কোর্সে SQL শিখতে কিছুই ইনস্টল করতে হয় না। প্রতিটি লাইভ এডিটর আপনার ব্রাউজারের ভেতরেই আসল SQLite চালায় — SQLite-কে WebAssembly-তে রূপান্তর করা একটি সংস্করণ (sql.js). প্রথমবার চালাতে ইঞ্জিনটি একবার ডাউনলোড হয়, তাই ইন্টারনেট লাগে; আপনার লেখা SQL বা ফল কোনো সার্ভারে যায় না। কয়েকটি নিয়ম জানলে এডিটরের আচরণ আর অবাক করবে না:

  • প্রতিবার নতুন ডেটাবেস। “চালান” চাপলে (বা কোড বদলালে, এক মুহূর্ত পরে নিজে থেকেই) একটি নতুন, খালি in-memory database তৈরি হয়, নমুনা ডেটা (db-shop বা db-uni) লোড হয়, তারপর আপনার স্টেটমেন্টগুলো একে একে চলে। আগের রানে যা ঢুকিয়েছিলেন বা মুছেছিলেন, পরের রানে তার কিছুই থাকে না — তাই নির্ভয়ে ভাঙচুর করুন।
  • প্রতিটি স্টেটমেন্টের আলাদা ফল। SELECT দেখায় একটি টেবিল, INSERT/UPDATE/DELETE দেখায় “কয়টি সারি বদলেছে”, CREATE-এর মতো DDL দেখায় একটি ✓.
  • প্রথম ত্রুটিতেই থামে। কোনো স্টেটমেন্টে ত্রুটি হলে তার পরেরগুলো আর চলে না।
  • “আগের কোড” বোতাম আপনার বদল মুছে মূল কোড ফিরিয়ে আনে। “নমুনা ডেটাবেস” বাক্স খুললে দেখবেন কোন টেবিলে কী আছে। Foreign key যাচাই চালু থাকে।
1SELECT COUNT(*) AS n FROM products;2INSERT INTO products VALUES3  (111, 'Tea 400g', 4, 240, 50);4SELEC name FROM products;5SELECT COUNT(*) AS n FROM products;
অবস্থা
ডেটাবেস
products-এ সারি
পর্দায় নতুন ফল
  1. নতুন, খালি ডেটাবেস। চালান চাপতেই মেমরিতে একটি নতুন SQLite ডেটাবেস তৈরি হয়, আর foreign key যাচাই চালু করা হয় (PRAGMA foreign_keys = ON). ডিস্কে কোনো ফাইল নেই, কোনো টেবিলও নেই।
  2. নমুনা ডেটা লোড। এডিটরের data-db অনুযায়ী db-shop-এর CREATE TABLE আর INSERT চলে: ৫টি টেবিল, products-এ ১০টি পণ্য। এই অংশের ফল পর্দায় দেখানো হয় না।
  3. স্টেটমেন্ট ১। SELECT চলে, পর্দায় একটি ছোট টেবিল আসে: n = 10.
  4. স্টেটমেন্ট ২। নতুন পণ্য Tea 400g (দাম ২৪০, Grocery শ্রেণি) ঢোকে: “✓ INSERT — ১টি সারি বদলেছে”। products-এ এখন ১১টি সারি — কিন্তু শুধু এই রানের ভেতরে।
  5. স্টেটমেন্ট ৩ — ত্রুটি। SELEC কোনো keyword নয়, parser থেমে যায়: near "SELEC": syntax error. ত্রুটি লাল রঙে দেখায়।
  6. স্টেটমেন্ট ৪ চলে না। প্রথম ত্রুটিতেই রান শেষ — ৪ নম্বরটির ফল আসে না। তাই একটি এডিটরে কয়েকটি ত্রুটি একসাথে দেখাতে চাইলে প্রতিটি আলাদা রানে দেখতে হবে।
  7. পরের রান — সব আবার নতুন। ৩ নম্বর ঠিক করে আবার চালালে আগের ডেটাবেস মুছে নতুন তৈরি হয়। Tea 400g আবার ঢোকে, তাই শেষ COUNT দেখাবে 11 — কিন্তু আগের রানের Tea আর নেই। নিজের কম্পিউটারের ডেটাবেসে এমন হয় না; সেখানে প্রতিটি পরিবর্তন ফাইলে থেকে যায় (অংশ ৭)।

আপনার প্রথম সেশন — টেবিল বানানো থেকে প্রশ্ন পর্যন্ত

এবার একদম খালি ডেটাবেসে (নমুনা ডেটা ছাড়া) একটি ছোট পুরো চক্র: একটি টেবিল বানানো (DDL), কয়েকটি সারি ঢোকানো (DML), আর প্রশ্ন করা (DQL). CREATE TABLE-এর খুঁটিনাটি পর্ব ১৩-এ, INSERT পর্ব ১৪-এ — এখানে শুধু পুরো পথটি একবার হেঁটে দেখুন:

CREATE TABLE friends (
  id    INTEGER PRIMARY KEY,
  name  TEXT NOT NULL,
  city  TEXT
);
INSERT INTO friends (id, name, city) VALUES (1, 'Rafi', 'Rajshahi');
INSERT INTO friends (id, name, city) VALUES
  (2, 'Mitu', 'Dhaka'),
  (3, 'Sakib', 'Sylhet');
SELECT * FROM friends;
SELECT name FROM friends WHERE city = 'Dhaka';

পাঁচটি স্টেটমেন্ট, পাঁচটি ফল: “✓ CREATE TABLE”, “✓ INSERT — ১টি সারি বদলেছে”, “✓ INSERT — ২টি সারি বদলেছে” (একটি INSERT-এ কয়েকটি সারি দেওয়া যায়), তারপর তিন সারির টেবিল 1 Rafi Rajshahi, 2 Mitu Dhaka, 3 Sakib Sylhet, আর শেষে শুধু Mitu. SELECT * মানে “সব কলাম” — দেখার জন্য সুবিধাজনক, তবে অ্যাপের কোডে কলামের নাম লিখে দেওয়াই ভালো (অংশ ৯)। এবার নিজে একটি চতুর্থ বন্ধু যোগ করে দেখুন, বা name ছাড়া একটি INSERT লিখে NOT NULL-এর ত্রুটি দেখুন।

৭ · নিজের কম্পিউটারে — SQLite, PostgreSQL আর MySQL

লাইভ এডিটর শেখার জন্য যথেষ্ট, কিন্তু আসল কাজ — নিজের প্রজেক্ট, বড় ডেটা, স্থায়ী ডেটাবেস — নিজের কম্পিউটারে করতে হয়। তিনটি জনপ্রিয় open-source DBMS-এর সেটআপ নিচে, প্রতিটির ভেতরে Windows, macOS আর Linux-এর পথ। সংস্করণ নম্বর দ্রুত বদলায়; নিচের নম্বরগুলো শুধু উদাহরণ — অফিসিয়াল সাইটে যেটি সর্বশেষ স্থিতিশীল সংস্করণ, সেটি নিন। কমান্ডগুলো চালানোর জিনিস নয় এই পাতায়, নিজের terminal-এ লিখবেন:

SQLite-এ কোনো server নেই: পুরো ডেটাবেস একটি সাধারণ ফাইল (shop.db), আর sqlite3 নামের ছোট একটি command-line প্রোগ্রাম সেটি খোলে। macOS আর বেশিরভাগ Linux-এ এটি আগে থেকেই থাকে।

# Windows: sqlite.org/download.html থেকে "sqlite-tools-win-x64-….zip" নামান,
#   ফোল্ডারে খুলে (যেমন C:\sqlite) সেই ফোল্ডারটি PATH-এ যোগ করুন
# macOS: সাধারণত আগে থেকেই আছে; নতুন সংস্করণ চাইলে
brew install sqlite
# Ubuntu / Debian
sudo apt install sqlite3

sqlite3 --version          # সংস্করণ দেখায় — ইনস্টল ঠিক আছে
sqlite3 shop.db            # shop.db খোলে (না থাকলে তৈরি করে)

GUI চাইলে DB Browser for SQLite (sqlitebrowser.org, বিনা মূল্যে, তিন OS-এ) — টেবিল দেখা, ডেটা হাতে বদলানো আর SQL চালানো যায়। Linux-এ sudo apt install sqlitebrowser.

PostgreSQL একটি পূর্ণ client-server DBMS. ইনস্টলের পর একটি server পেছনে চলতে থাকে, আর psql (terminal client) বা pgAdmin (GUI) দিয়ে তার সাথে সংযোগ করেন।

# Windows: postgresql.org/download/windows থেকে EDB installer —
#   এতে server, psql আর pgAdmin 4 একসাথে; ইনস্টলের সময় দেওয়া
#   postgres ব্যবহারকারীর password মনে রাখুন। পরে Start মেনুতে "SQL Shell (psql)"
# macOS: Postgres.app (postgresapp.com), অথবা Homebrew —
brew install postgresql@17          # সংখ্যাটি বর্তমান সংস্করণে বদলে নিন
brew services start postgresql@17
# Ubuntu / Debian
sudo apt install postgresql
sudo -u postgres psql               # postgres নামের admin হিসেবে psql খোলে

psql-এ backslash দিয়ে শুরু কিছু meta-command আছে, যেগুলো SQL নয়, তাই সেমিকোলন লাগে না:

CREATE DATABASE shop;   -- SQL: সেমিকোলন লাগে
\l                      -- সব ডেটাবেসের তালিকা
\c shop                 -- shop ডেটাবেসে যান
\dt                     -- এই ডেটাবেসের টেবিলগুলো
\d products             -- একটি টেবিলের কলাম, টাইপ, index
\?                      -- সব meta-command-এর সাহায্য
\q                      -- বের হওয়া

MySQL (এখন Oracle-এর মালিকানায়) আর তার open-source শাখা MariaDB প্রায় একই ভাষা বোঝে। শেয়ার্ড হোস্টিং, WordPress আর PHP-র জগতে এরাই সবচেয়ে প্রচলিত। Terminal client mysql (MariaDB-তে mariadb), GUI হলো MySQL Workbench.

# Windows: dev.mysql.com/downloads থেকে MySQL Community Server-এর MSI installer;
#   root password দিন। Workbench আলাদা ডাউনলোড।
# macOS
brew install mysql
brew services start mysql
mysql -u root                       # প্রথমে password ছাড়া; পরে mysql_secure_installation
# Ubuntu: MySQL, অথবা Debian-এর ডিফল্ট MariaDB
sudo apt install mysql-server       # অথবা: sudo apt install mariadb-server
sudo mysql                          # Linux-এ root সাধারণত sudo দিয়েই ঢোকে
SHOW DATABASES;        -- সব ডেটাবেস
CREATE DATABASE shop;
USE shop;              -- shop ডেটাবেসে যান
SHOW TABLES;           -- টেবিলের তালিকা
DESCRIBE products;     -- টেবিলের কলাম আর টাইপ
exit

কিছু ইনস্টল না করেই অন্য DBMS চেখে দেখতে চাইলে দুই রকম পথ আছে:

  • অনলাইন fiddle: DB Fiddle, dbfiddle.uk বা SQL Fiddle-এর মতো সাইটে ব্রাউজারে PostgreSQL, MySQL, SQL Server-এর বিভিন্ন সংস্করণে কোয়েরি চালানো যায়, আর একটি লিংক দিয়ে অন্যকে দেখানো যায় — প্রশ্ন করার সময় খুব কাজের।
  • Cloud DBMS-এর বিনা মূল্যের স্তর: বেশ কিছু কোম্পানি ছোট PostgreSQL বা MySQL ডেটাবেস বিনা মূল্যে চালাতে দেয় (যেমন Neon, Supabase, Aiven). শর্ত আর সীমা প্রায়ই বদলায়, তাই নেওয়ার আগে বর্তমান নিয়ম পড়ে নিন, আর আসল ব্যক্তিগত ডেটা সেখানে রাখবেন না। বিস্তারিত পর্ব ৬১-এ।

SQLite CLI-তে প্রথম সেশন

sqlite3-এ SQL ছাড়াও ডট (.) দিয়ে শুরু কিছু meta-command আছে — psql-এর backslash কমান্ডের মতো। নিচের ডায়াগ্রামে একটি পুরো সেশন দেখুন:

Terminalলাল = এই ধাপে নতুন

            
  1. ফাইল খোলা। sqlite3 shop.db লিখলে shop.db না থাকলে নতুন তৈরি হয় (আসলে প্রথম লেখার সময়)। sqlite> prompt মানে sqlite3 আপনার কমান্ডের অপেক্ষায়।
  2. .tables — টেবিলের তালিকা। নতুন ফাইল, তাই কিছুই নেই। ডট-কমান্ড SQL নয়, sqlite3 প্রোগ্রামের নিজের কমান্ড — সেমিকোলন লাগে না, আর শুধু লাইনের শুরুতে লেখা যায়।
  3. কয়েক লাইনে CREATE TABLE. প্রথম লাইনের শেষে সেমিকোলন নেই, তাই prompt বদলে ...> হলো — “স্টেটমেন্ট এখনো শেষ হয়নি, আরও লিখুন”। শেষ লাইনে ; পেয়ে তবেই চলল। psql-এ একই অবস্থায় prompt হয় shop-#, mysql-এ ->.
  4. INSERT. তিনটি সারি একসাথে। সফল হলে sqlite3 কিছুই বলে না — নীরবতাই সাফল্য।
  5. .headers on আর .mode column. ডিফল্টে sqlite3 ফল দেখায় কলামের নাম ছাড়া, মানগুলো খাড়া দাগ দিয়ে জোড়া। এই দুটি কমান্ডে কলামের নামসহ সুন্দর সারিবদ্ধ টেবিল আসে। নতুন সংস্করণে .mode box বা .mode table-ও আছে।
  6. .schema friends. টেবিলটি যে CREATE TABLE দিয়ে তৈরি, সেটিই ফেরত দেখায় — অন্যের বানানো ডেটাবেস বুঝতে প্রথম কমান্ড। .schema একা লিখলে সব টেবিলের।
  7. বের হয়ে আবার খোলা। .quit-এর পর shop.db ফাইলটি ডিস্কে আছে, আর আবার খুললে ৩টি সারিই পাওয়া যায়। লাইভ এডিটরের সাথে বড় পার্থক্য এটিই: এখানে ডেটা স্থায়ী।

এডিটর আর GUI টুল

Terminal ছাড়াও অনেকে GUI পছন্দ করেন — টেবিলের গঠন দেখা, ফল spreadsheet-এর মতো ঘোরানো, আর কোয়েরি সংরক্ষণ সহজ হয়:

DBeaver Community

বিনা মূল্যের, এক টুলেই SQLite, PostgreSQL, MySQL, SQL Server, Oracle সহ বহু DBMS. কয়েকটি ডেটাবেস নিয়ে কাজ করলে সুবিধাজনক।

Windows · macOS · Linux

pgAdmin / MySQL Workbench

নির্দিষ্ট DBMS-এর নিজস্ব GUI. pgAdmin PostgreSQL-এর জন্য, Workbench MySQL-এর জন্য (MariaDB-তে কিছু অংশ ঠিকমতো কাজ না-ও করতে পারে)।

DBMS-এর সাথে মানানসই

VS Code extension

কোড লেখার এডিটরেই ডেটাবেস: SQLTools আর তার driver, SQLite দেখার extension, আর বড় DBMS-গুলোর নিজস্ব extension. অ্যাপ বানানোর সময় এক জানালায় সব।

ডেভেলপারদের প্রিয়

কোনটি ইনস্টল করবেন?

আপনার লক্ষ্যশুরু করুনকেন
শুধু SQL শেখা, এই কোর্সলাইভ এডিটর, তারপর SQLite + DB Browserকোনো server, password বা port নেই; একটি ফাইলই ডেটাবেস
বিশ্ববিদ্যালয়ের ল্যাব বা চাকরির পরীক্ষাল্যাবে যেটি ব্যবহার হয় (প্রায়ই MySQL, Oracle বা PostgreSQL)ব্যবহারিক পরীক্ষায় সেই DBMS-এর উপভাষাই লাগবে
ওয়েব অ্যাপ (PHP, WordPress, Laravel)MySQL বা MariaDBশেয়ার্ড হোস্টিং আর cPanel-এ সাধারণত এটিই দেওয়া থাকে
ওয়েব অ্যাপ (Django, Node, Rails, Spring)PostgreSQLশক্ত standard-মানা, JSON, শক্তিশালী index আর extension
ডেটা বিশ্লেষণ, রিপোর্টPostgreSQL; বড় ফাইল বিশ্লেষণে DuckDB-ও দেখুনwindow function, CTE; বিশ্লেষণধর্মী embedded ইঞ্জিন
মোবাইল, ডেস্কটপ বা যন্ত্রের ভেতরেSQLiteAndroid আর iOS-এ আগে থেকেই আছে; অ্যাপের সাথেই চলে
ব্যাংক বা বড় প্রতিষ্ঠানের কাজOracle বা SQL Server-এর বিনা মূল্যের সংস্করণঅনেক বড় প্রতিষ্ঠান এগুলো ব্যবহার করে; শেখার জন্য ফ্রি সংস্করণ আছে

ভালো খবর: এই কোর্সের বেশিরভাগ SQL তিনটি DBMS-এই একইভাবে চলে। একটিতে ভালোভাবে শিখলে অন্যটিতে যেতে কয়েক দিনের অভ্যাসই যথেষ্ট — পার্থক্যগুলো পর্ব ৩১-এ একসাথে পাবেন।

৮ · Error message পড়া — ভুলটা কোন ধাপের

নতুনরা লাল লেখা দেখে ভয় পান, অথচ error message হলো DBMS-এর সবচেয়ে সৎ সাহায্য। তিনটি অভ্যাস গড়ুন: (১) বার্তার প্রথম অংশ পড়ুন — কোন ধরনের ভুল; (২) বার্তায় উদ্ধৃত শব্দটি খুঁজুন — “near …” বা নামটি; (৩) অংশ ৫-এর ছবি মনে করুন — ব্যাকরণ, নাম, নাকি চলার সময়। প্রথমে ব্যাকরণের syntax error:

-- প্রথমটি ঠিক আছে
SELECT name FROM categories WHERE category_id = 1;

-- দ্বিতীয়টিতে একটি অক্ষর বাদ পড়েছে
SELEC name FROM products;

-- এটি আর চলবেই না
SELECT name FROM products;

প্রথম স্টেটমেন্টের ফল আসে (Electronics), তারপর ত্রুটি: near "SELEC": syntax error, আর তৃতীয়টি চলেই না। “near” মানে parser ঠিক এই token-এ এসে আটকেছে। মনে রাখবেন, ভুলটা কখনো কখনো উদ্ধৃত শব্দের আগে থাকে — যেমন আগের লাইনে একটি কমা বা বন্ধনী বাদ পড়লে parser পরের শব্দে গিয়ে অভিযোগ করে। তাই “near”-এর শব্দ আর তার ঠিক আগের অংশ, দুটিই দেখুন।

এবার নামের ভুল। এর আগে একটি নীরব ভুল দেখুন, যা কোনো ত্রুটিই দেয় না — আর সেজন্যই বেশি বিপজ্জনক:

-- কমা বাদ পড়েছে: ত্রুটি নেই, কিন্তু ফল ভুল!
SELECT name price FROM products WHERE product_id = 104;

-- টেবিলের নামে বানান ভুল: product (s নেই)
SELECT name, price FROM product;

প্রথমটি দিব্যি চলে, কিন্তু ফলে কলাম একটিই, যার মাথায় লেখা price আর মান DSA Book! কারণ name price মানে “name কলাম, যার নতুন নাম (alias) price” — SQL-এ AS লেখা ঐচ্ছিক। দ্বিতীয়টিতে ত্রুটি: no such table: product. ব্যাকরণ ঠিক ছিল, কিন্তু catalog-এ এই নামের টেবিল নেই। কলামের বানান ভুল হলে (যেমন prise) একইভাবে আসে no such column: prise. সমাধান: .tables বা .schema দিয়ে আসল নাম দেখে নিন।

তৃতীয় সাধারণ ভুল আসে দুটি টেবিল একসাথে পড়ার সময় — JOIN, যা পর্ব ১৯-এ বিস্তারিত শিখবেন। products আর categories দুটি টেবিলেই name নামে কলাম আছে:

-- ঠিক: কোন টেবিলের name, তা বলে দেওয়া আছে
SELECT products.name, categories.name AS category
FROM products
JOIN categories ON products.category_id = categories.category_id
WHERE products.price > 4000;

-- ভুল: কোন name? দুটি টেবিলেই আছে
SELECT name FROM products
JOIN categories ON products.category_id = categories.category_id;

প্রথমটিতে দুটি সারি: Mobile Phone | Electronics আর Saree | Clothing. দ্বিতীয়টিতে ত্রুটি: ambiguous column name: name — “দ্ব্যর্থক”, অর্থাৎ DBMS বুঝতে পারছে না আপনি কোন টেবিলের name চান। এটিও নামের ধাপের ভুল। সমাধান products.name বা ছোট alias দিয়ে (p.name) কলামকে টেবিলের নামসহ লেখা। একাধিক টেবিলের কোয়েরিতে সব কলাম এভাবে লেখা ভালো অভ্যাস।

একই ভুলের বার্তা একেক DBMS-এ একেক রকম। চেনা থাকলে যেকোনো সিস্টেমে কাজ করতে পারবেন:

ভুলSQLitePostgreSQLMySQL
ব্যাকরণnear "SELEC": syntax errorsyntax error at or near "SELEC"ERROR 1064 (42000): You have an error in your SQL syntax … near 'SELEC …'
টেবিল নেইno such table: productrelation "product" does not existERROR 1146 (42S02): Table 'shop.product' doesn't exist
কলাম নেইno such column: prisecolumn "prise" does not existERROR 1054 (42S22): Unknown column 'prise' in 'field list'
দ্ব্যর্থক কলামambiguous column name: namecolumn reference "name" is ambiguousERROR 1052 (23000): Column 'name' in field list is ambiguous

MySQL-এর বন্ধনীর ভেতরের পাঁচ অক্ষরের কোডটি হলো SQLSTATE — standard-নির্ধারিত error কোড। PostgreSQL-ও একই রকম কোড দেয় (যেমন syntax error-এর জন্য 42601, টেবিল না থাকলে 42P01). অ্যাপের কোডে বার্তার লেখা নয়, এই কোড দেখে সিদ্ধান্ত নিন — বার্তা সংস্করণ বদলালে বদলাতে পারে, কোড সাধারণত বদলায় না।

৯ · প্রথম কোয়েরিগুলো আর SQL লেখার ধরন

কোনো অচেনা ডেটাবেস হাতে পেলে পেশাদাররা প্রথমে তিনটি কাজ করেন: কোন কোন টেবিল আছে, একটি টেবিলের কয়েকটি সারি কেমন, আর মোটামুটি কত ডেটা। SQLite-এ টেবিলের তালিকা থাকে sqlite_master নামের catalog টেবিলে — .tables কমান্ড ভেতরে এটিই পড়ে:

-- কোন কোন টেবিল আছে? (SQLite-এর catalog)
SELECT name FROM sqlite_master WHERE type = 'table';

-- একটি টেবিলের প্রথম কয়েকটি সারি
SELECT * FROM customers LIMIT 3;

-- কোন অবস্থায় কয়টি অর্ডার?
SELECT status, COUNT(*) AS n
FROM orders
GROUP BY status
ORDER BY status;

প্রথম ফলে পাঁচটি নাম: customers, categories, products, orders, order_items. দ্বিতীয়টিতে প্রথম তিন গ্রাহক — Rahim Uddin (Dhaka), Karima Begum (Chattogram), Sabbir Hasan (Dhaka) — তাঁদের ফোন আর যোগদানের তারিখসহ। LIMIT 3 বড় টেবিলে খুব জরুরি: কোটি সারির টেবিলে SELECT * একা চালালে পর্দা আর নেটওয়ার্ক দুটিই আটকে যায়। তৃতীয়টি একটি সারাংশ: cancelled 1, delivered 5, pending 2, shipped 2 — মোট ১০টি অর্ডার। GROUP BY পর্ব ১৮-এ শিখবেন। PostgreSQL-এ টেবিলের তালিকা আসে information_schema.tables থেকে, MySQL-এ SHOW TABLES দিয়ে।

এবার বিশ্ববিদ্যালয়ের ডেটাবেস (db-uni), যা পরের অনেক পর্বে ব্যবহার হবে। এতে পাঁচটি টেবিল: departments (dept_id, name, building — CSE, EEE, BBA, English), instructors (instructor_id, name, dept_id, salary, mentor_id — mentor_id একই টেবিলের আরেক শিক্ষককে দেখায়), students (student_id, name, dept_id, batch, cgpa — ৮ জন), courses (course_id, title, dept_id, credits, instructor_id — ৭টি কোর্স) আর enrollments (student_id, course_id, term, grade — কে কোন term-এ কোন কোর্স নিয়েছেন; grade NULL মানে ফল আসেনি)।

-- CSE বিভাগের (dept_id 1) শিক্ষার্থী, CGPA বেশি থেকে কম
SELECT student_id, name, batch, cgpa
FROM students
WHERE dept_id = 1
ORDER BY cgpa DESC;

-- CSE-র কোর্সগুলো, কে পড়ান (instructor_id)
SELECT course_id, title, credits, instructor_id
FROM courses
WHERE dept_id = 1
ORDER BY course_id;

প্রথম ফলে CSE-র চারজন: 2201 Dilruba Khatun 2022 3.9, 2101 Arif Hossain 2021 3.75, 2301 Gulshan Ara 2023 3.55, 2102 Bristy Saha 2021 3.4. দ্বিতীয় ফলে চারটি কোর্স: CSE101 (৩ ক্রেডিট, শিক্ষক 2), CSE201 (৩, শিক্ষক 1), CSE301 (৩, শিক্ষক 6) আর CSE302 Database Systems Lab (১.৫, শিক্ষক 6). শিক্ষকের নাম দেখতে instructors টেবিল জুড়তে হবে — সেটিই JOIN-এর কাজ। এবার নিজে dept_id = 1 বদলে 2 লিখে EEE-র ফল দেখুন।

SQL style guide — যেভাবে লিখলে অন্যরা (আর ছয় মাস পরের আপনি) পড়তে পারবেন

DBMS-এর কাছে ফাঁকা জায়গা বা বড়-ছোট অক্ষরের কোনো মূল্য নেই, কিন্তু মানুষের কাছে আছে। প্রতিষ্ঠানভেদে নিয়ম একটু আলাদা হয়, তবে নিচেরগুলো ব্যাপকভাবে প্রচলিত:

নিয়মভালোএড়িয়ে চলুন
Keyword বড় হাতের, নাম ছোট হাতেরSELECT name FROM productsselect Name from PRODUCTS
নাম snake_case-এ, quote ছাড়া চলে এমনorder_items, unit_price"Order Items", UnitPrice
প্রতিটি clause নতুন লাইনেSELECT … ⏎ FROM … ⏎ WHERE …এক লাইনে ২০০ অক্ষর
অ্যাপের কোডে কলামের নাম লিখুনSELECT name, priceSELECT * (কলাম যোগ হলে অ্যাপ ভাঙে)
Alias-এ AS লিখুনprice * 2 AS double_priceprice * 2 double_price
একাধিক টেবিলে কলামের আগে টেবিলp.name, c.nameশুধু name
সবসময় ; দিয়ে শেষ…ORDER BY price;শেষ স্টেটমেন্টে সেমিকোলন বাদ

এখানকার সব উদাহরণ এই নিয়ম মেনে লেখা। দলে কাজ করলে একটি formatter বা linter (যেমন SQLFluff) সবার লেখা এক রকম রাখতে সাহায্য করে।

১০ · AI-এর যুগে SQL শেখা আর লেখা

“গত মাসে কোন পণ্য সবচেয়ে বেশি বিক্রি হয়েছে, SQL লিখে দাও” — AI কয়েক সেকেন্ডে লিখে দেয়, আর কোয়েরিটি প্রায়ই চলেও। বিপদটা সেখানেই: চলা মানেই সঠিক নয়. অংশ ৮-এর কমা-বাদ-পড়া কোয়েরিও চলেছিল। AI-এর লেখা SQL-এ সাধারণত যা ভুল হয়:

AI-এর ভুলফলকীভাবে ধরবেন
নেই এমন কলাম বা টেবিলের নাম বানিয়ে নেয় (customer_name, sales)no such column — বা কাছাকাছি নামের ভুল কলামে চলেPrompt-এ আসল schema দিন; .schema মিলিয়ে নিন
উপভাষা মিশিয়ে ফেলে (TOP, LIMIT, NOW())syntax error বা অন্য অর্থDBMS আর সংস্করণ বলে দিন
NULL ভুলে যায় (= NULL, NULL-ওয়ালা সারি বাদ)চলে, কিন্তু সারি হারায়NULL আছে এমন সারি দিয়ে পরীক্ষা (পর্ব ১৬)
JOIN-এ duplicate বা হারানো সারিযোগফল দ্বিগুণ বা কমJOIN-এর আগে-পরে সারি গুনুন (COUNT(*))
Index আর transaction উপেক্ষাবড় ডেটায় ধীর; অর্ধেক কাজ হয়ে থেমে যাওয়াEXPLAIN দেখুন; বদলের কাজ BEGIN … COMMIT-এ

AI-কে SQL চাইলে প্রেক্ষাপট দিন, আর যাচাইয়ের উপায়ও চেয়ে নিন:

আমি SQLite 3 ব্যবহার করছি (পরে PostgreSQL-এ নেব)। আমার টেবিল: products(product_id, name, category_id, price, stock) orders(order_id, customer_id, order_date, status) order_items(order_id, product_id, quantity, unit_price) প্রশ্ন: ২০২৫ সালের সেপ্টেম্বরে বাতিল নয় এমন অর্ডারে কোন পণ্য কত টাকার বিক্রি হয়েছে, বেশি থেকে কম। ১. শুধু এই কলামগুলোই ব্যবহার করো, নতুন কলাম বানিও না। ২. কোয়েরির প্রতিটি অংশ এক লাইনে ব্যাখ্যা করো। ৩. NULL, বাতিল অর্ডার আর একই পণ্য কয়েক অর্ডারে থাকলে কী হবে — বলো। ৪. ফল হাতে মিলিয়ে দেখার জন্য একটি ছোট পরীক্ষার কোয়েরিও দাও। ৫. SQLite আর PostgreSQL-এ লেখায় কোনো পার্থক্য থাকলে আলাদা করে দেখাও।

AI-এর দেওয়া SQL চালানোর আগে — যাচাইয়ের চেকলিস্ট

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • SQL কি procedural না declarative? — Declarative: কী চাই বলে, কীভাবে আনবে তা optimizer ঠিক করে।
  • DDL, DML, DCL, TCL-এর উদাহরণ দিন। — CREATE/ALTER/DROP; INSERT/UPDATE/DELETE (আর SELECT, কেউ বলেন DQL); GRANT/REVOKE; COMMIT/ROLLBACK.
  • SQL আর MySQL-এর পার্থক্য? — SQL একটি ভাষা (standard); MySQL একটি RDBMS সফটওয়্যার, যা SQL-এর একটি উপভাষা বোঝে।
  • Single quote আর double quote-এর পার্থক্য? — Single quote-এ string মান; standard SQL-এ double quote-এ নাম (identifier).
  • Window function কোন standard-এ এসেছে? — SQL:2003; recursive CTE আর trigger এসেছে SQL:1999-এ।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১প্রোগ্রামিং ভাষা আসে-যায়, কিন্তু ১৯৭০-এর দশকের SQL আজও প্রায় প্রতিটি ডেটাবেসের ভাষা। Declarative নকশা এই দীর্ঘ আয়ুর পেছনে কতটা দায়ী?

অনেকটাই। SQL-এর আগে CODASYL-এর মতো network ডেটাবেসে প্রোগ্রামার লিখতেন কোন record থেকে কোন pointer ধরে কোথায় যেতে হবে (পর্ব ২, ৪)। ডেটার গঠন বা ডিস্কে সাজানো বদলালে সেই কোডও বদলাতে হতো। Codd-এর মূল যুক্তি ছিল: ব্যবহারকারী শুধু বলবেন কোন ডেটা চাই, কীভাবে আনা হবে তা সিস্টেমের ব্যাপার। এটিই data independence (পর্ব ৩)।

এর একটি বড় সুফল কেউ তখন পুরোপুরি কল্পনা করেননি: হার্ডওয়্যার বদলালেও পুরোনো কোয়েরি অক্ষত থাকে, আর দ্রুততর হয়। ১৯৮০-র দশকের একটি SELECT আজ চলে SSD-তে, বহু CPU core-এ, কয়েক গিগাবাইট মেমরিতে — অথচ লেখাটি একই। Index যোগ হলে, optimizer উন্নত হলে, parallel execution এলে — ব্যবহারকারীর এক লাইনও বদলাতে হয় না। Procedural কোডে প্রতিটি নতুন কৌশল কাজে লাগাতে কোড নতুন করে লিখতে হতো।

অন্য কারণগুলোও আছে। ১৯৮৬-র standard বহু কোম্পানিকে একই ভাষায় বেঁধে দেয়, ফলে দক্ষতা এক প্রতিষ্ঠান থেকে আরেকটিতে নেওয়া যায়। Berkeley-র Ingres-এর QUEL ভাষাকে অনেক গবেষক বেশি পরিচ্ছন্ন মনে করতেন, কিন্তু IBM-এর প্রভাব আর standard-এর জোরে SQL জিতে যায় — প্রযুক্তিতে “সবচেয়ে ভালো” নয়, “সবচেয়ে প্রচলিত” প্রায়ই টেকে। আর ২০১০-এর দশকে যখন অনেক NoSQL সিস্টেম SQL বাদ দিয়ে এসেছিল, তাদের অনেকেই পরে SQL-এর মতো কোয়েরি ভাষা যোগ করেছে, কারণ ব্যবহারকারীরা সেটিই চেয়েছেন।

দাম কিন্তু আছে: optimizer ভুল plan বাছলে কোয়েরি হঠাৎ ধীর হয়ে যায়, আর কারণ খুঁজতে plan পড়তে শিখতে হয় (পর্ব ৪৩)। Declarative মানে দায়িত্ব শেষ নয়, দায়িত্ব বদল।

মূল উপলব্ধি: “কী চাই” আর “কীভাবে করব” আলাদা রাখায় SQL-এর কোয়েরি হার্ডওয়্যার আর অ্যালগরিদমের উন্নতির সুফল বিনা পরিশ্রমে পায় — এটিই তার পঞ্চাশ বছরের আয়ুর মূল রহস্য।

প্র ০২SQL-এর আন্তর্জাতিক standard আছে প্রায় চার দশক ধরে। তবু একই কোয়েরি SQLite-এ চলে, SQL Server-এ চলে না — এমন হয় কেন?

প্রথম কারণ ইতিহাস। Oracle, IBM-এর DB2 আর আরও কয়েকটি পণ্য ১৯৮৬-র standard-এর আগেই বাজারে ছিল, নিজস্ব শব্দ আর রীতি নিয়ে। Standard এলে তাদের পুরোনো লেখা বাতিল করা অসম্ভব ছিল — হাজার হাজার গ্রাহকের কোড ভেঙে যেত। তাই প্রায় প্রতিটি DBMS standard যোগ করেছে, কিন্তু নিজের পুরোনো উপভাষাও রেখে দিয়েছে। SQL Server-এর TOP, MySQL-এর backtick আর LIMIT, Oracle-এর পুরোনো ROWNUM এমন উত্তরাধিকার।

দ্বিতীয় কারণ standard নিজেই। আধুনিক SQL standard বহু অংশে ভাগ করা বিশাল দলিল, আর ISO এটি বিনা মূল্যে দেয় না। SQL-92-এ সমর্থনের তিনটি স্তর ছিল — Entry, Intermediate, Full — আর বেশিরভাগ পণ্য শুধু Entry স্তর দাবি করত। পরের সংস্করণগুলোতে একটি “core” আর অনেক ঐচ্ছিক feature, ফলে “standard মানে” বলা প্রায় অর্থহীন হয়ে যায়: কোন feature, কোন অংশ? আমেরিকার NIST একসময় SQL-এর সামঞ্জস্য পরীক্ষা করত, কিন্তু নব্বইয়ের দশকের মাঝামাঝি তা বন্ধ হয়ে যায় — তারপর থেকে কোম্পানিগুলোর দাবি যাচাইয়ের নিরপেক্ষ কোনো ব্যবস্থা প্রায় নেই।

তৃতীয় কারণ ব্যবসা। নিজস্ব সুবিধাজনক feature গ্রাহকদের টানে, আর একবার সেগুলো ব্যবহার করলে অন্য DBMS-এ যাওয়া কঠিন হয়। আবার উল্টো দিকও আছে: PostgreSQL-এর মতো সিস্টেম নতুন feature আনার সময় সাধারণত standard-এর লেখাটিই বেছে নেয়, আর SQLite অন্যদের লেখাও বুঝে নেয়, যাতে কোড সহজে আনা যায়।

ব্যবহারিক শিক্ষা: বহনযোগ্য (portable) কোড চাইলে standard লেখা পছন্দ করুন — FETCH FIRST, '' escape, CASE, COALESCE — আর DBMS-নির্দিষ্ট অংশ এক জায়গায় আলাদা রাখুন।

মূল উপলব্ধি: SQL standard একটি সাধারণ ভিত্তি, পূর্ণ চুক্তি নয়। প্রতিটি DBMS-এ “এখানে কোনটি চলে” যাচাই করাই পেশাদারি অভ্যাস।

প্র ০৩প্রায় প্রতিটি স্মার্টফোনে SQLite আছে, তবু ব্যস্ত ওয়েবসাইটের মূল ডেটাবেস হিসেবে সাধারণত PostgreSQL বা MySQL বেছে নেওয়া হয়। SQLite-এর শক্তি আর সীমা কোথায়?

SQLite-এর নির্মাতারা নিজেরাই একটি সুন্দর তুলনা দেন: SQLite প্রতিযোগিতা করে client-server ডেটাবেসের সাথে নয়, বরং সাধারণ ফাইল খোলার (fopen()) সাথে। অর্থাৎ যেখানে একটি অ্যাপ নিজের ডেটা নিজের কাছে রাখে — ফোনের কন্টাক্ট, ব্রাউজারের ইতিহাস, ডেস্কটপ সফটওয়্যারের সেটিং, যন্ত্রের লগ — সেখানে আলাদা server চালানো অপ্রয়োজনীয় ঝামেলা। SQLite একটি library, অ্যাপের সাথেই চলে, পুরো ডেটাবেস একটি ফাইল, কোনো password বা port নেই। Android আর iOS দুটিতেই এটি সিস্টেমের অংশ, আর নির্মাতাদের দাবি অনুযায়ী এটি পৃথিবীর সবচেয়ে বেশি ব্যবহৃত ডেটাবেস ইঞ্জিন।

সীমা আসে একসাথে অনেক লেখক থাকলে। SQLite-এ যেকোনো মুহূর্তে পুরো ডেটাবেসে একটিমাত্র লেখার transaction চলতে পারে। WAL mode চালু করলে পড়ার কাজ লেখার সময়ও চলে, কিন্তু লেখকেরা লাইনে দাঁড়ায়। হাজার ব্যবহারকারীর ওয়েবসাইটে প্রতি সেকেন্ডে অনেক অর্ডার, অনেক লগইন একসাথে লিখলে এটি বাধা হয়ে দাঁড়ায়। তাছাড়া কয়েকটি ওয়েব সার্ভার এক ডেটাবেস ভাগ করতে চাইলে নেটওয়ার্কে রাখা ফাইলে SQLite নির্ভরযোগ্য নয় — নির্মাতারাই সতর্ক করেন। User আর GRANT-এর মতো অনুমতি ব্যবস্থাও নেই।

PostgreSQL আর MySQL ঠিক এই কাজের জন্য: অনেক client একসাথে, সারি-স্তরের lock আর MVCC (পর্ব ৪৭), ব্যবহারকারী-ভিত্তিক অনুমতি, replication (পর্ব ৫২)। তবে সীমাটি অনেকে অতিরঞ্জিত করেন — কম-লেখা, বেশি-পড়া মাঝারি ওয়েবসাইট এক সার্ভারে SQLite দিয়ে ভালোভাবেই চলতে পারে, আর সাম্প্রতিক বছরগুলোতে এমন ব্যবহার বাড়ছে।

মূল উপলব্ধি: “কোন DBMS সেরা” প্রশ্নটি ভুল; ঠিক প্রশ্ন হলো “কতজন একসাথে লিখবে, ডেটা কোথায় থাকবে, কে কী দেখতে পারবে?” এক লেখকের নিজস্ব ডেটায় SQLite অপ্রতিদ্বন্দ্বী, অনেক লেখকের ভাগাভাগির ডেটায় client-server.

প্র ০৪একজন ডেভেলপার Windows ল্যাপটপে MySQL দিয়ে অ্যাপ বানালেন, সব ঠিক চলল। Linux সার্ভারে তুলতেই “Table doesn't exist”. আরেকজন PostgreSQL-এ CREATE TABLE "Customers" লিখে পরে SELECT * FROM Customers চালিয়ে একই রকম ত্রুটি পেলেন। নামের বড়-ছোট অক্ষর নিয়ে এই গোলমালের উৎস কী?

Keyword case-insensitive — এ নিয়ে কোনো DBMS-এ মতভেদ নেই। কিন্তু নাম (identifier) নিয়ে নিয়ম আলাদা। SQL standard বলে, quote ছাড়া লেখা নাম বড় হাতের অক্ষরে রূপান্তরিত (fold) হবে — customers আসলে CUSTOMERS; আর quote-সহ নাম যেমন লেখা তেমনই থাকবে। Oracle এই নিয়ম মানে। PostgreSQL উল্টো দিকে যায়: quote ছাড়া নাম ছোট হাতে রূপান্তরিত হয়। তাই "Customers" (বড় C সহ, quote-এ) তৈরি করলে টেবিলটির আসল নাম Customers, কিন্তু পরে FROM Customers (quote ছাড়া) লিখলে PostgreSQL খোঁজে customers — পায় না। এরপর থেকে প্রতিবার quote দিয়ে লিখতে হবে।

MySQL-এর গল্প আরও মজার। এখানে প্রতিটি ডেটাবেস একটি ফোল্ডার, আর টেবিলের তথ্য ফাইল হিসেবে থাকে (ইঞ্জিনভেদে)। তাই টেবিলের নামের case-sensitivity নির্ভর করে অপারেটিং সিস্টেমের ফাইল সিস্টেমের ওপর, যা lower_case_table_names সেটিং দিয়ে নিয়ন্ত্রিত। Windows-এ ফাইলের নাম case-insensitive, তাই সেখানে Orders আর orders একই; Linux-এ ডিফল্টে আলাদা। ফলে কোডে একবার Orders আর আরেকবার orders লিখলে Windows-এ দিব্যি চলে, Linux সার্ভারে ভাঙে। কলামের নাম অবশ্য MySQL-এ সবখানেই case-insensitive. SQLite-এ নাম সবসময় case-insensitive.

সমাধান সহজ আর সর্বজনীন: সব নাম ছোট হাতের snake_case-এ রাখুন (order_items), quote ছাড়াই চলে এমন — space, বাংলা অক্ষর বা keyword নাম হিসেবে ব্যবহার করবেন না। তাহলে standard-এর বড় হাতের fold, PostgreSQL-এর ছোট হাতের fold, আর MySQL-এর ফাইল সিস্টেম — কোনোটিই আপনাকে ধরতে পারবে না। আর ডেভেলপমেন্ট পরিবেশ যতটা সম্ভব সার্ভারের মতো রাখুন (একই OS বা container).

মূল উপলব্ধি: Quote দেওয়া নাম একটি স্থায়ী প্রতিশ্রুতি — একবার quote দিয়ে বড় অক্ষর রাখলে সারা জীবন quote দিতে হবে। ছোট হাতের snake_case এই পুরো সমস্যাকে মূল থেকে সরিয়ে দেয়।

প্র ০৫অনেকে বলেন “SQL প্রোগ্রামিং ভাষা নয়, শুধু query ভাষা।” এই দাবি কতটা ঠিক? আর AI যখন সাধারণ ভাষা থেকেই SQL লিখে দেয়, তখন SQL শেখার দরকার কতটা?

মূল SQL (SQL-92 পর্যন্ত) সত্যিই সীমিত ছিল। এতে loop বা recursion ছিল না, তাই কিছু সহজ-মনে-হওয়া প্রশ্নও লেখা যেত না — যেমন “একজন শিক্ষকের mentor, তাঁর mentor, তাঁরও mentor… সবার তালিকা”, যেখানে কয় স্তর আছে আগে জানা নেই। তত্ত্বে relational algebra (পর্ব ৩২) এমন transitive closure প্রকাশ করতে পারে না — এটি পরিচিত একটি সীমা।

SQL:1999-এ WITH RECURSIVE আসার পর পরিস্থিতি বদলায়। Recursive CTE (পর্ব ২৫) দিয়ে তত্ত্বে যেকোনো গণনা প্রকাশ করা যায় — দেখানো হয়েছে যে recursive CTE আর window function-ওয়ালা SQL Turing-complete. শখের মানুষেরা SQL দিয়ে Mandelbrot ছবি থেকে সুডোকু সমাধান পর্যন্ত করেছেন। তার ওপর প্রায় প্রতিটি বড় DBMS-এর আছে পূর্ণ procedural সম্প্রসারণ — Oracle-এর PL/SQL, SQL Server-এর T-SQL, PostgreSQL-এর PL/pgSQL, আর standard-এর SQL/PSM — যেখানে variable, loop, শর্ত সবই আছে (পর্ব ২৮)। তাই “প্রোগ্রামিং ভাষা নয়” কথাটি তাত্ত্বিকভাবে আর ঠিক নয়; তবে SQL-এর শক্তি সেখানে নয়, সেটের ওপর ঘোষণামূলক প্রশ্নে।

এবার AI. সাধারণ ভাষা থেকে SQL বানানো (text-to-SQL) নিয়ে গবেষণা দশকের পর দশক চলছে, আর বড় ভাষা-মডেল একে অনেক কার্যকর করেছে। কিন্তু অংশ ১০-এ দেখেছেন, ভুলগুলো নীরব: চলা কোয়েরি, ভুল সংখ্যা। একটি বিক্রির রিপোর্টে duplicate-এর কারণে আয় দ্বিগুণ দেখালে সেটি কে ধরবেন? যিনি SQL পড়তে পারেন, NULL আর JOIN-এর আচরণ জানেন, আর ফলকে সন্দেহ করতে জানেন। AI লেখা দ্রুত করে, কিন্তু যাচাইয়ের দক্ষতা আরও মূল্যবান করে তোলে।

মূল উপলব্ধি: SQL আজ তত্ত্বে পূর্ণ গণনার ক্ষমতা রাখে, কিন্তু তার আসল জোর ঘোষণামূলক প্রশ্নে। AI-এর যুগে SQL লেখার চেয়ে SQL পড়া আর যাচাই করার দক্ষতাই বেশি দামি।

অনুশীলন

একটি ফল আগে বলা, একটি কোয়েরি লেখা, একটি ভুল খোঁজা, একটি সিদ্ধান্ত।

  1. ফল আগে বলুন (trace): db-shop-এর একটি লাইভ এডিটরে (products-এ ১০টি পণ্য) এই চারটি স্টেটমেন্ট চালানো হলো: (ক) DELETE FROM products WHERE price > 4000; (খ) SELECT COUNT(*) FROM products; (গ) SELECT nme FROM products; (ঘ) SELECT COUNT(*) FROM products; পর্দায় কী কী আসবে? তারপর একই কোড আবার চালালে (খ)-এর ফল কত?

    (ক) দাম ৪০০০-এর বেশি দুটি পণ্য — Mobile Phone (15000) আর Saree (4500). কিন্তু দুটিই অর্ডারে আছে (order_items-এ 101 আর 107), আর foreign key চালু, তাই পুরো DELETE বাতিল: FOREIGN KEY constraint failed. প্রথম ত্রুটিতেই রান থামে — (খ), (গ), (ঘ) কোনোটিই চলে না!

    এটিই ফাঁদ: অনেকে ভাবেন (খ) দেখাবে 8, (গ)-তে no such column: nme. কিন্তু দুটি ভুলই হিসাব করতে হয় ক্রমানুসারে। আবার চালালেও একই ফল, কারণ প্রতিবার নতুন ডেটাবেস। চাইলে price > 4000-এর বদলে product_id = 103 (Power Bank, কোনো অর্ডারে নেই) লিখে দেখুন: তখন “১টি সারি বদলেছে”, (খ) 9, তারপর (গ)-তে no such column: nme, আর (ঘ) চলবে না।

  2. কোয়েরি লিখুন: db-uni-এর students টেবিল (student_id, name, dept_id, batch, cgpa) থেকে ২০২২ ব্যাচের শিক্ষার্থীদের নাম আর CGPA নামের বর্ণানুক্রমে দেখান। উপরের db-uni এডিটরে চালিয়ে মিলিয়ে নিন।
    SELECT name, cgpa
    FROM students
    WHERE batch = 2022
    ORDER BY name;

    ফল: Dilruba Khatun | 3.9, Emon Mia | 3.1, Fahim Karim | NULL. Fahim-এর CGPA এখনো নেই (NULL) — তবু তিনি তালিকায় আছেন, কারণ শর্তটি batch-এর ওপর। 2022 সংখ্যা, তাই quote লাগেনি; batch কলামটি INTEGER.

  3. ভুল খুঁজুন: একজন সহকর্মী PostgreSQL-এ লিখলেন: SELECT name price FROM Products WHERE city = "Dhaka" — উদ্দেশ্য ঢাকার পণ্যের নাম আর দাম দেখা (ধরুন টেবিলটি products নামে তৈরি, আর এতে city কলামও আছে)। কয়টি সমস্যা আছে, আর কোনটি ত্রুটি দেবে?
    • name price: কমা নেই, তাই price এখানে name-এর alias — ত্রুটি দেবে না, শুধু একটি কলাম আসবে। ঠিক: name, price.
    • Products: PostgreSQL quote ছাড়া নাম ছোট হাতে নেয়, তাই এটি products-ই — সমস্যা নয় (কিন্তু ধারাবাহিকতার জন্য ছোট হাতে লিখুন)।
    • "Dhaka": PostgreSQL-এ double quote মানে নাম, তাই ত্রুটি: column "Dhaka" does not exist. ঠিক: 'Dhaka'. (SQLite এটি string ধরে চালিয়ে দিত — ভুলটা লুকিয়ে থাকত।)
    • শেষে ; নেই: psql-এ prompt -# হয়ে অপেক্ষা করবে।

    সংশোধিত: SELECT name, price FROM products WHERE city = 'Dhaka';

  4. সিদ্ধান্ত নিন: তিনটি পরিস্থিতিতে কোন DBMS দিয়ে শুরু করবেন, এক লাইনে কারণসহ: (ক) একটি অফলাইন Android অ্যাপ, যা দোকানের দৈনিক বিক্রির হিসাব ফোনেই রাখবে; (খ) একটি শেয়ার্ড হোস্টিং-এ চলা WordPress সাইট; (গ) একটি অনলাইন শপের API, যেখানে কয়েকটি সার্ভার একসাথে অর্ডার লিখবে।

    (ক) SQLite — একজন ব্যবহারকারী, ফোনের ভেতরে ডেটা, ইন্টারনেট ছাড়া; Android-এ আগে থেকেই আছে। (খ) MySQL বা MariaDB — WordPress এগুলোর জন্যই তৈরি, আর শেয়ার্ড হোস্টিং-এ সাধারণত এটিই দেওয়া থাকে। (গ) PostgreSQL (বা MySQL) — অনেক লেখক একসাথে, নেটওয়ার্কে সংযোগ, অনুমতি আর transaction-এর দৃঢ় নিয়ন্ত্রণ দরকার; নেটওয়ার্কে ভাগ করা SQLite ফাইল এখানে ঝুঁকিপূর্ণ।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি SELECT স্টেটমেন্ট টাইপ করার পর DBMS-এর ভেতরের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Client স্টেটমেন্টটি server-এ (বা SQLite library-তে) পাঠায়
  2. Parser ব্যাকরণ যাচাই করে parse tree বানায়, catalog দেখে নাম মেলায়
  3. Optimizer সম্ভাব্য পথগুলোর খরচ হিসাব করে একটি query plan বাছে
  4. Executor plan মেনে সারি পড়ে আর শর্ত যাচাই করে
  5. Result set client-এ ফেরত যায়

SQL-কে declarative ভাষা বলা হয় কেন?

  • এর keyword-গুলো ইংরেজি শব্দ
  • এতে কী চাই বলা হয়, কীভাবে আনা হবে তা DBMS ঠিক করে
  • এতে কোনোভাবেই loop লেখা যায় না
  • এটি ANSI আর ISO-র standard

নিচের কোনটি standard SQL-এ সঠিকভাবে লেখা একটি string literal, যার মান Rahim's Shop?

  • "Rahim's Shop"
  • 'Rahim\'s Shop'
  • 'Rahim''s Shop'
  • `Rahim's Shop`

SQLite-এ SELECT name price FROM products; চালালে (products-এ name আর price দুটি কলামই আছে) কী হবে?

  • একটি কলামই আসবে, যার মাথায় লেখা price কিন্তু মানগুলো পণ্যের নাম
  • syntax error
  • name আর price দুটি কলামই আসবে
  • no such column: price

Window function (যেমন ROW_NUMBER() OVER (…)) প্রথম কোন SQL standard সংস্করণে আসে?

  • SQL-92
  • SQL:1999
  • SQL:2011
  • SQL:2003

psql-এ একটি কোয়েরি লিখে Enter চাপার পর prompt shop=# থেকে বদলে shop-# হলো, কোনো ফলও এল না। সবচেয়ে সম্ভাব্য কারণ কী?

  • server-এর সাথে সংযোগ বিচ্ছিন্ন হয়েছে
  • স্টেটমেন্টের শেষে সেমিকোলন দেওয়া হয়নি
  • কোয়েরিতে syntax error আছে
  • টেবিলে কোনো সারি নেই

একটি অফলাইন মোবাইল অ্যাপ, যা একজন ব্যবহারকারীর ডেটা ফোনেই রাখবে — এর জন্য কোন DBMS সবচেয়ে মানানসই?

  • PostgreSQL
  • MySQL
  • SQLite
  • Oracle Database

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. SQL একটি declarative ভাষা, কোনো সফটওয়্যার নয়; SQLite, PostgreSQL, MySQL হলো RDBMS, যারা SQL-এর নিজস্ব উপভাষা বোঝে।
  2. পাঁচ ভাগ: DDL, DML, DQL, DCL, TCL. ইতিহাস: SEQUEL ১৯৭৪ → ANSI ১৯৮৬ → SQL-92 → SQL:1999 (recursive, trigger) → SQL:2003 (window) → SQL:2023.
  3. Keyword case-insensitive, ডেটার মান নয়; string '…'-এ (ভেতরের ' লিখতে ''), নাম দরকারে "…"-এ; comment -- আর /* */; স্টেটমেন্ট শেষে ;.
  4. স্টেটমেন্টের পথ: client → server/library → parser → optimizer → executor → result. Error-এর ধাপ চিনুন: syntax, নাম (no such table/column, ambiguous), নাকি চলার সময়।
  5. শেখা শুরু লাইভ এডিটর আর SQLite দিয়ে; ওয়েবে PostgreSQL বা MySQL. নীরব ভুল (কমা বাদ, double-quote string) সবচেয়ে বিপজ্জনক — চালিয়ে, গুনে, যাচাই করুন।

পরের পর্বে: এবার নিজের টেবিল ঠিকভাবে বানানোর পালা। পর্ব ১৩-এ CREATE TABLE — কোন কলামের কোন ডেটা টাইপ, SQLite-এর নমনীয় টাইপ বনাম PostgreSQL আর MySQL-এর কঠোর টাইপ, আর NOT NULL, UNIQUE, CHECK, DEFAULT দিয়ে ডেটার পাহারা।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান