অধ্যায় 2 · ডেটা পড়া
সাজানো আর পেজিং: ORDER BY, LIMIT ও OFFSET
- পৃষ্ঠা 6 / 22
- 14 মিনিট পড়া
টেবিল হলো সারির একটা সেট, আর সেটের কোনো ক্রম থাকে না। আপনি ক্রম না চাইলে ডেটাবেস সেই মুহূর্তে তার জন্য যেটা সবচেয়ে সুবিধাজনক, সেই ক্রমেই সারি ফেরত দেয়; কোনো আপডেট, নতুন ইনডেক্স বা ভার্সন আপগ্রেডের পর সেই ক্রম বদলেও যেতে পারে। ক্রম চাওয়ার উপায় হলো ORDER BY, আর সেই ক্রমের শুধু প্রথম কয়েকটা সারি চাওয়ার উপায় LIMIT।
এই দুটো আপনি সারাক্ষণ একসাথে ব্যবহার করবেন: "সবচেয়ে নতুন ১০টা সাপোর্ট টিকিট", "এই সপ্তাহের সবচেয়ে দামি ২০টা LLM কল", "প্রোডাক্ট লিস্টের ৩ নম্বর পাতা", ভেক্টর সার্চে "সবচেয়ে কাছের ৫টা ডকুমেন্ট"। ট্রেনিং ডেটা প্রতিবার একই নির্দিষ্ট ক্রমে এক্সপোর্ট করা গেলে তবেই একটা ML এক্সপেরিমেন্ট আবার চালিয়ে একই ফল পাওয়া (reproducible) সহজ হয়।
যা শিখবেন
ORDER BYদিয়ে ছোট থেকে বড় ও বড় থেকে ছোট, একাধিক কলাম ধরে, আর এক্সপ্রেশন বা অ্যালিয়াস ধরে সাজানো।- টাই-ব্রেকার যোগ করে ক্রমটা পুরোপুরি নির্দিষ্ট করা।
- SQLite, MySQL আর PostgreSQL-এ
NULLমান কোথায় বসে, আর কীভাবে সরানো যায়। LIMITদিয়ে প্রথম N সারি নেওয়া, আর এর অন্য রূপ:FETCH FIRST,TOP।OFFSETদিয়ে পাতায় পাতায় ফলাফল দেখানো, আর বড় অফসেট কেন ধীর এবং কেন সারি বাদ পড়ে বা দুবার আসে।
ORDER BY না থাকলে ক্রমের কোনো নিশ্চয়তা নেই
SQLite-এ SELECT name FROM products; চালালে সারিগুলো সম্ভবত product_id-এর ক্রমেই আসবে। এটা এই ছোট টেবিলটা SQLite যেভাবে রাখে তার একটা কাকতালীয় ফল, কোনো প্রতিশ্রুতি নয়। PostgreSQL-এ তো প্রায়ই সদ্য আপডেট হওয়া সারিগুলো শেষে আসে। নিয়মটা সোজা: ক্রম গুরুত্বপূর্ণ হলে ORDER BY লিখুন। এই টিউটোরিয়ালে একাধিক সারি ফেরত দেয় এমন প্রতিটা কোয়েরিতেই সেটা আছে।
ORDER BY: ছোট থেকে বড়, বড় থেকে ছোট
ORDER BY column ছোট থেকে বড়তে সাজায়। এটাই ASC (ascending), ডিফল্ট, তাই সাধারণত লিখতে হয় না। DESC (descending) সাজায় বড় থেকে ছোটতে:
SELECT name, price
FROM products
ORDER BY price DESC;+-----------------------------+-------+
| name | price |
+-----------------------------+-------+
| 27-inch Monitor | 18500 |
| AI Engineering Bootcamp | 15000 |
| Noise-Cancelling Headphones | 7500 |
| Mechanical Keyboard | 4500 |
| SQL Masterclass | 3000 |
| Hands-On Machine Learning | 2500 |
| USB-C Hub | 2200 |
| Laptop Stand | 1500 |
| Python Crash Course | 1200 |
| Gift Card | 1000 |
| Wireless Mouse | 900 |
+-----------------------------+-------+"ছোট" মানে কী, তা টাইপের ওপর নির্ভর করে: সংখ্যা সাজে মান অনুযায়ী, টেক্সট সাজে অক্ষর ধরে ধরে (তাই '27-inch Monitor' আসে 'AI Engineering Bootcamp'-এর আগে, কারণ অঙ্ক অক্ষরের আগে), আর '2026-03-08'-এর মতো ISO তারিখ সাজে ক্যালেন্ডারের ক্রমে। যে কলাম SELECT করেননি, তা দিয়েও ORDER BY করা যায়।
SELECT name
FROM customers
ORDER BY joined_on DESC -- সবচেয়ে নতুন কাস্টমার আগে; joined_on দেখানো হচ্ছে না
LIMIT 3;+---------------+
| name |
+---------------+
| Karim Uddin |
| Mitu Das |
| Imran Hossain |
+---------------+একাধিক কলাম আর টাই-ব্রেকার
একাধিক কলাম দিলে ডেটাবেস প্রথমটা ধরে সাজায়; প্রথম কলামে যে সারিগুলোর মান সমান, শুধু সেগুলোর ক্রম ঠিক করতে দ্বিতীয়টা ব্যবহার করে, এভাবে চলতে থাকে। প্রতিটা কলামের দিক আলাদা করে ঠিক করা যায়:
SELECT department, name, salary
FROM employees
ORDER BY department, salary DESC;+-------------+-----------------+--------+
| department | name | salary |
+-------------+-----------------+--------+
| Data | Lamia Karim | 160000 |
| Data | Priya Sen | 110000 |
| Data | Shuvo Roy | 95000 |
| Engineering | Hasan Mahmud | 180000 |
| Engineering | Nusrat Jahan | 120000 |
| Engineering | Zahid Hasan | 120000 |
| Management | Ayesha Siddiqua | 250000 |
+-------------+-----------------+--------+ডিপার্টমেন্ট A থেকে Z; প্রতিটা ডিপার্টমেন্টের ভেতরে সবচেয়ে বেশি বেতন আগে। এবার নুসরাত আর জাহিদকে দেখুন: দুজনেরই বেতন ১,২০,০০০। কে আগে আসবে, এই কোয়েরির কোথাও তা বলা নেই, তাই ডেটাবেস যেকোনো ক্রমে দিতে পারে, আর অন্য ডেটাবেস অন্য ক্রম বাছতে পারে। একটা টাই-ব্রেকার যোগ করুন, অর্থাৎ শেষে এমন একটা কলাম যার মান ইউনিক, যেমন প্রাইমারি কি:
SELECT department, name, salary
FROM employees
ORDER BY department, salary DESC, employee_id;+-------------+-----------------+--------+
| department | name | salary |
+-------------+-----------------+--------+
| Data | Lamia Karim | 160000 |
| Data | Priya Sen | 110000 |
| Data | Shuvo Roy | 95000 |
| Engineering | Hasan Mahmud | 180000 |
| Engineering | Nusrat Jahan | 120000 |
| Engineering | Zahid Hasan | 120000 |
| Management | Ayesha Siddiqua | 250000 |
+-------------+-----------------+--------+এখন ক্রমটা পুরোপুরি নির্দিষ্ট। এটা যতটা মনে হয় তার চেয়ে বেশি জরুরি: অস্থির ক্রমের কারণেই একটা টেস্ট আপনার ল্যাপটপে পাস করে কিন্তু CI-তে ফেল করে, লিস্টের ২ নম্বর পাতায় ১ নম্বর পাতার সারি আবার আসে, আর "একই" ট্রেনিং সেটের দুটো এক্সপোর্ট আলাদা হয়ে যায়।
ASCআরDESCখাটে একটা কলামে।ORDER BY department, salary DESCমানে department ছোট থেকে বড়, salary বড় থেকে ছোট। দুটো কলামই উল্টো হয় না।
এক্সপ্রেশন বা অ্যালিয়াস ধরে সাজানো
হিসাব করা মান ধরেও সাজানো যায়। নিচে অর্ডারের প্রতিটা লাইনের মোট (quantity × unit price), যে লাইনের মোট সবচেয়ে বেশি সেটা আগে:
SELECT order_id, product_id, quantity * unit_price AS line_total
FROM order_items
ORDER BY line_total DESC, order_id, product_id
LIMIT 5;+----------+------------+------------+
| order_id | product_id | line_total |
+----------+------------+------------+
| 5 | 5 | 18500 |
| 10 | 5 | 18500 |
| 6 | 7 | 15000 |
| 13 | 7 | 15000 |
| 2 | 3 | 4500 |
+----------+------------+------------+অ্যালিয়াস line_total দিয়ে সাজানো যায়, কারণ কোয়েরির লজিক্যাল ক্রমে (দেখুন SQL কীভাবে কাজ করে: স্টেটমেন্ট, কমান্ডের ধরন আর কোয়েরির ক্রম) ORDER BY চলে SELECT-এর পরে, তাই অ্যালিয়াসটা ততক্ষণে তৈরি হয়ে গেছে। চাইলে ORDER BY quantity * unit_price DESC, এমনকি ORDER BY 3 DESC (SELECT-এর তৃতীয় কলাম) লিখতে পারেন। আসল কোডে সংখ্যার রূপটা এড়িয়ে চলুন: SELECT-এ একটা কলাম যোগ করলেই কোয়েরি চুপচাপ অন্য কিছু ধরে সাজাতে শুরু করে।
NULL কোথায় যায়?
কোর্সগুলো আর গিফট কার্ডের স্টকের কোনো হিসাব নেই (NULL)। stock ধরে সাজালে এই সারিগুলো কোথায় বসবে, তা নিয়ে ডেটাবেসগুলো একমত নয়:
| ডেটাবেস | ORDER BY stock (ASC) | ORDER BY stock DESC | NULLS FIRST / LAST লেখা যায়? |
|---|---|---|---|
| SQLite | NULL আগে | NULL শেষে | হ্যাঁ (3.30+) |
| MySQL | NULL আগে | NULL শেষে | না |
| PostgreSQL | NULL শেষে | NULL আগে | হ্যাঁ |
| SQL Server | NULL আগে | NULL শেষে | না |
SQLite আর MySQL NULL-কে যেকোনো মানের চেয়ে ছোট ধরে; PostgreSQL ধরে বড়। PostgreSQL-এ একই কোয়েরি:
-- PostgreSQL
SELECT name, stock
FROM products
ORDER BY stock, product_id
LIMIT 5;+-----------------------------+-------+
| name | stock |
+-----------------------------+-------+
| USB-C Hub | 0 |
| 27-inch Monitor | 5 |
| Noise-Cancelling Headphones | 8 |
| Mechanical Keyboard | 12 |
| Hands-On Machine Learning | 15 |
+-----------------------------+-------+SQLite আর PostgreSQL-এ NULLS FIRST বা NULLS LAST দিয়ে ঠিক কী চান তা বলে দিতে পারেন:
SELECT name, stock
FROM products
ORDER BY stock NULLS LAST, product_id;+-----------------------------+-------+
| name | stock |
+-----------------------------+-------+
| USB-C Hub | 0 |
| 27-inch Monitor | 5 |
| Noise-Cancelling Headphones | 8 |
| Mechanical Keyboard | 12 |
| Hands-On Machine Learning | 15 |
| Laptop Stand | 25 |
| Python Crash Course | 40 |
| Wireless Mouse | 60 |
| SQL Masterclass | NULL |
| AI Engineering Bootcamp | NULL |
| Gift Card | NULL |
+-----------------------------+-------+MySQL-এ NULLS LAST লেখাই যায় না। সব ডেটাবেসে চলে এমন কৌশল হলো আগে "এটা কি NULL?" ধরে সাজানো। আসল মানের জন্য stock IS NULL হয় 0, NULL-এর জন্য 1, তাই NULL-গুলো শেষে চলে যায়:
-- MySQL
SELECT name, stock
FROM products
ORDER BY stock IS NULL, stock, product_id;+-----------------------------+-------+
| name | stock |
+-----------------------------+-------+
| USB-C Hub | 0 |
| 27-inch Monitor | 5 |
| Noise-Cancelling Headphones | 8 |
| Mechanical Keyboard | 12 |
| Hands-On Machine Learning | 15 |
| Laptop Stand | 25 |
| Python Crash Course | 40 |
| Wireless Mouse | 60 |
| SQL Masterclass | NULL |
| AI Engineering Bootcamp | NULL |
| Gift Card | NULL |
+-----------------------------+-------+এটা SQLite আর PostgreSQL-এও চলে। ফলাফল যখন কোনো রিপোর্ট বা মডেলে যাবে, অনুপস্থিত মান কোথায় বসবে তা নিজে ঠিক করুন আর কোয়েরিতে লিখে দিন; ডেটাবেসের ডিফল্টের ভরসায় ছেড়ে দেবেন না।
LIMIT: শুধু প্রথম N সারি
LIMIT n সাজানো ফলাফলের প্রথম nটা সারি রাখে। ORDER BY-এর সাথে এটা "টপ N" প্রশ্নের উত্তর দেয়:
-- সবচেয়ে দামি তিনটা প্রোডাক্ট
SELECT name, price
FROM products
ORDER BY price DESC
LIMIT 3;+-----------------------------+-------+
| name | price |
+-----------------------------+-------+
| 27-inch Monitor | 18500 |
| AI Engineering Bootcamp | 15000 |
| Noise-Cancelling Headphones | 7500 |
+-----------------------------+-------+LIMIT চলে সবার শেষে, সাজানোর পরে। এ কারণেই "টপ ৩" কাজ করে: ডেটাবেস সব সারি সাজায়, তারপর কাটে। ORDER BY ছাড়া LIMIT মানে স্রেফ "যেকোনো ৩টা সারি"; টেবিলে এক ঝলক চোখ বোলাতে ঠিক আছে, অন্য সব কাজে ভুল।
LIMIT-এর অন্য রূপ
LIMIT SQL স্ট্যান্ডার্ডের অংশ নয়, তাই ডায়ালেক্টভেদে আলাদা। স্ট্যান্ডার্ড রূপ হলো FETCH FIRST n ROWS ONLY:
| ডেটাবেস | প্রথম ৩টা সারি | ৩টা বাদ দিয়ে পরের ৩টা |
|---|---|---|
| SQLite, PostgreSQL, MySQL | LIMIT 3 | LIMIT 3 OFFSET 3 |
| MySQL (এটাও) | LIMIT 3 | LIMIT 3, 3 (অফসেট আগে!) |
| PostgreSQL, Oracle 12c+ (স্ট্যান্ডার্ড) | FETCH FIRST 3 ROWS ONLY | OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY |
| SQL Server | SELECT TOP 3 … | OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY (ORDER BY লাগবে) |
স্ট্যান্ডার্ড রূপটা PostgreSQL-এ চলে, আর এটা এমন একটা কাজ পারে যা LIMIT পারে না। ধরুন সবচেয়ে বেশি বেতন পান এমন চারজন কর্মী চাইলেন, কিন্তু চতুর্থ স্থানে দুজনের বেতন সমান।
-- PostgreSQL
SELECT name, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 4 ROWS WITH TIES;+-----------------+--------+
| name | salary |
+-----------------+--------+
| Ayesha Siddiqua | 250000 |
| Hasan Mahmud | 180000 |
| Lamia Karim | 160000 |
| Zahid Hasan | 120000 |
| Nusrat Jahan | 120000 |
+-----------------+--------+WITH TIES (PostgreSQL 13+, SQL Server-এ TOP 4 WITH TIES) শেষ সারির সমান মানের সব সারি রেখে দেয়, তাই আপনি পান ৫টা সারি। আরও খেয়াল করুন, PostgreSQL জাহিদকে নুসরাতের আগে দেখিয়েছে: টাই-ব্রেকার না থাকলে সমান সারিগুলো ইঞ্জিনের সুবিধামতো ক্রমে আসে। LIMIT 4 চুপচাপ দুজনের একজনকে বাদ দিত, আর কাকে বাদ দেবে তা ডেটাবেসের মর্জি। লিডারবোর্ড বা "সেরা কাস্টমার" বোনাসের বেলায় এটা সত্যিকারের বাগ: যোগ্য একজন কোনো কারণ ছাড়াই বাদ পড়েন।
OFFSET দিয়ে পেজিং
OFFSET m প্রথম mটা সারি বাদ দেয়। প্রতি পাতায় kটা সারি থাকলে p নম্বর পাতা হলো LIMIT k OFFSET (p − 1) × k। একটা ওয়েব পেজ বা API এভাবেই "প্রতি পাতায় ৫টা অর্ডার" দেখায়। Python-এ সংখ্যাগুলো প্যারামিটার হিসেবে পাঠান:
from sqlhelp import con
def orders_page(page, size=5):
"""অর্ডারের এক পাতা, সবচেয়ে নতুনটা আগে।"""
rows = con.execute(
"""SELECT order_id FROM orders
ORDER BY order_date DESC, order_id DESC
LIMIT ? OFFSET ?""",
(size, (page - 1) * size),
).fetchall()
return [r[0] for r in rows]
for page in (1, 2, 3, 4):
print(f"page {page}:", orders_page(page))page 1: [14, 13, 12, 11, 10]
page 2: [9, 8, 7, 6, 5]
page 3: [4, 3, 2, 1]
page 4: []১৪টা অর্ডারে হয় দুটো ভরা পাতা, ৪টার একটা পাতা, আর খালি ৪ নম্বর পাতা। খালি পাতা পেলেই ফাংশনটা যে কোড ডাকছে, সে বোঝে এবার থামতে হবে। টাই-ব্রেকার order_id DESC খেয়াল করুন: এটা না থাকলে একই দিনের দুটো অর্ডার দুই রিকোয়েস্টের মাঝে জায়গা বদল করে দুই পাতায় আসতে পারত, অথবা কোনো পাতাতেই না।
OFFSET-এর দুটো খরচ
যত গভীরে যাবেন, তত ধীর। OFFSET 100000 দিতে ডেটাবেসকে তবুও প্রথম ১,০০,০০০টা সারি খুঁজে সাজাতে হয়, তারপর সেগুলো ফেলে দিতে হয়। ১ নম্বর পাতা দ্রুত; ৫,০০০ নম্বর পাতা নয়।
ডেটা বদলালে সারি বাদ পড়তে বা দুবার আসতে পারে। কেউ ১ নম্বর পাতা দেখে ২ নম্বরে যাওয়ার আগেই একটা নতুন অর্ডার এলে কী হয়, দেখুন:
print("page 1:", orders_page(1))
con.execute("INSERT INTO orders VALUES (15, 4, '2026-06-20', 'pending')") # একটা নতুন অর্ডার এল
print("page 2:", orders_page(2))
con.execute("DELETE FROM orders WHERE order_id = 15") # ডেটা আগের অবস্থায় ফেরানো
con.commit()page 1: [14, 13, 12, 11, 10]
page 2: [10, 9, 8, 7, 6]১০ নম্বর অর্ডার দুই পাতাতেই এসেছে: নতুন অর্ডারটা বাকি সবাইকে এক ঘর নিচে ঠেলে দিয়েছে। দুটো সমস্যারই সমাধান কি-সেট পেজিনেশন (keyset pagination): "৫টা সারি বাদ দিয়ে পরেরগুলো"-র বদলে চান "শেষ যেটা দেখেছি, তার পরের সারিগুলো", যেমন WHERE order_id < 10 ORDER BY order_id DESC LIMIT 5। এতে লাগে WHERE, যা পরের পাতায় শিখবেন; অ্যাডভান্সড টিউটোরিয়ালে দুই পদ্ধতির ঠিকঠাক তুলনা আছে। ছোট অ্যাডমিন স্ক্রিনের জন্য OFFSET একদম ঠিক আছে।
কোথায় কাজে লাগবে
- ড্যাশবোর্ড আর API: "সর্বশেষ ২০টা অর্ডার", "ফলাফলের ৩ নম্বর পাতা"। প্রতিটা লিস্ট এন্ডপয়েন্টে একটা ORDER BY আর একটা LIMIT থাকে।
- LLM মনিটরিং: সবচেয়ে ধীর বা সবচেয়ে দামি ১০টা মডেল কল (
ORDER BY latency_ms DESC LIMIT 10) থেকেই সমস্যা খোঁজা শুরু হয়। - ভেক্টর সার্চ: pgvector-সহ PostgreSQL-এ "সবচেয়ে কাছের ৫টা চাঙ্ক খুঁজে বের করা" আক্ষরিক অর্থেই
ORDER BY embedding <=> :query LIMIT 5। - ডেটা ঘেঁটে দেখা:
LIMIT 10হলোdf.head()-এর SQL রূপ। কিন্তু প্রথম ১,০০০টা সারি কোনো র্যান্ডম স্যাম্পল নয়: প্রায়ই এগুলো সবচেয়ে পুরোনো সারি। "প্রথম N সারি" দিয়ে কখনো মডেল ট্রেন বা মূল্যায়ন করবেন না।
সাধারণ ভুল
- ORDER BY ছাড়া LIMIT। সাজানো ছাড়া "টপ ৫" মানে যেকোনো ৫টা সারি। সবসময় দুটো একসাথে লিখুন:
ORDER BY price DESC LIMIT 5। - টাই-ব্রেকার নেই। যে কলামে মান বারবার আসে (তারিখ, বেতন, স্ট্যাটাস), তা দিয়ে সাজালে সমান সারিগুলো এলোমেলো ক্রমে থাকে, আর পাতাগুলো একটার ওপর আরেকটা পড়ে। শেষে একটা ইউনিক কলাম দিন:
ORDER BY order_date DESC, order_id DESC। - ভাবা যে DESC সব কলামে খাটে।
ORDER BY department, salary DESCdepartment সাজায় ছোট থেকে বড়তে। যে কলামের দিক বদলাতে চান, প্রতিটার পরে আলাদা করে লিখুন। - MySQL-এর
LIMIT a, bউল্টো পড়া।LIMIT 10, 5মানে ১০টা বাদ দিয়ে ৫টা নেওয়া; উল্টোটা নয়।LIMIT 5 OFFSET 10লিখুন: পড়তে পরিষ্কার, আর তিন ডেটাবেসেই চলে। - টেক্সট হিসেবে রাখা সংখ্যা টেক্সটের মতো সাজে।
'10'আসে'9'-এর আগে, কারণ'1'<'9':SELECT column1 AS version FROM (VALUES ('9'), ('10'), ('100')) ORDER BY version;সংখ্যা রাখুন সংখ্যার কলামে। তা না পারলে+---------+ | version | +---------+ | 10 | | 100 | | 9 | +---------+CAST(version AS INTEGER)ধরে সাজান (CAST নিয়ে আরও আছে টেক্সট, সংখ্যা ও তারিখের ফাংশন, CAST আর COALESCE পাতায়)।
নিজে চেষ্টা করুন
- সহজ: সব পেমেন্ট দেখান, সবচেয়ে বড় amount আগে। সমান হলে
payment_idদিয়ে ক্রম ঠিক করুন। - মাঝারি: নাম অনুযায়ী সাজানো প্রোডাক্ট লিস্টের ২ নম্বর পাতা দেখান, প্রতি পাতায় ৪টা প্রোডাক্ট (কলাম
nameআরprice)। - মাঝারি: প্রোডাক্টগুলো স্টক অনুযায়ী বেশি থেকে কমে সাজান, আর যেগুলোর স্টকের হিসাব নেই সেগুলো একদম শেষে রাখুন, এমনভাবে যাতে MySQL-এও চলে।
- কঠিন:
LIMITআরOFFSETদিয়ে দ্বিতীয় সবচেয়ে দামি প্রোডাক্টটা বের করুন। তারপর ব্যাখ্যা করুন,employees-এLIMIT 1 OFFSET 1দিয়ে "দ্বিতীয় সর্বোচ্চ বেতনের কর্মী" চাওয়াটা কেন ন্যায্য প্রশ্ন, কিন্তুLIMIT 1 OFFSET 3দিয়ে "চতুর্থ সর্বোচ্চ বেতনের কর্মী" চাওয়াটা কেন নয়।
উত্তর
-- 1
SELECT payment_id, order_id, amount
FROM payments
ORDER BY amount DESC, payment_id;
-- 2: ২ নম্বর পাতায় প্রথম ৪টা বাদ
SELECT name, price
FROM products
ORDER BY name, product_id
LIMIT 4 OFFSET 4;
-- 3: "stock IS NULL" হয় 0 নয়তো 1, তাই NULL শেষে যায়
SELECT name, stock
FROM products
ORDER BY stock IS NULL, stock DESC, product_id;
-- 4
SELECT name, price
FROM products
ORDER BY price DESC
LIMIT 1 OFFSET 1;৪-এর জন্য: বড় থেকে ছোট ক্রমে বেতন ২,৫০,০০০, ১,৮০,০০০, ১,৬০,০০০, ১,২০,০০০, ১,২০,০০০, … দ্বিতীয় সারি নিঃসন্দেহে হাসান মাহমুদ। চতুর্থ আর পঞ্চম সারি সমান, তাই "চতুর্থ সর্বোচ্চ বেতনের কর্মী" নুসরাতও হতে পারেন, জাহিদও; LIMIT 1 OFFSET 3 কিছু না জানিয়ে একজনকে বেছে নেয়। ভালো প্রশ্ন হলো "চতুর্থ সর্বোচ্চ আলাদা বেতন কত" (SELECT DISTINCT salary … LIMIT 1 OFFSET 3, উত্তর ১,২০,০০০) অথবা "কে কে ১,২০,০০০ পান"।
সারসংক্ষেপ
ORDER BYছাড়া সারির ক্রম নির্ধারিত নয়। যে ক্রম দরকার, তা চেয়ে নিন।ASCডিফল্ট;DESCউল্টে দেয়; প্রতিটা কলামের দিক আলাদা। শেষে একটা ইউনিক টাই-ব্রেকার দিন।- এক্সপ্রেশন আর
SELECT-এর অ্যালিয়াস ধরে সাজানো যায়, কারণ ORDER BY চলে SELECT-এর পরে। - ছোট থেকে বড় সাজালে SQLite আর MySQL-এ NULL আগে আসে, PostgreSQL-এ শেষে। বেছে নিতে
NULLS LASTবাORDER BY col IS NULL, colব্যবহার করুন। LIMIT n OFFSET mদিয়ে টপ-N লিস্ট আর পেজিং দুটোই হয়। বড় অফসেট ধীর, আর ডেটা বদলালে পাতা সরে যায়; কিসেট পেজিনেশন দুটোই ঠিক করে।
এরপর: সারি বাছাই: WHERE, AND, OR ও NOT। এতক্ষণ প্রতিটা কোয়েরি সব সারি দেখেছে। এবার আপনি ঠিক করবেন কোন সারিগুলো রাখবেন, তারপর শুধু সেগুলোকেই সাজাবেন আর সীমিত করবেন।