অধ্যায় 2 · ডেটা পড়া
SELECT: কলাম, এক্সপ্রেশন, অ্যালিয়াস আর DISTINCT
- পৃষ্ঠা 5 / 22
- 15 মিনিট পড়া
অন্য যেকোনো স্টেটমেন্টের চেয়ে বেশি লিখবেন SELECT। মডেলের জন্য যে ডেটাসেট তোলেন, ড্যাশবোর্ডের প্রতিটা সংখ্যা, একটা AI এজেন্ট যে সারিগুলো পড়ে — সবকিছুর শুরু একটা SELECT দিয়ে। এই পাতায় আছে ফলাফলের প্রতিটা সারির চেহারা ঠিক করার অংশটা: কোন কলামগুলো নেবেন, কোন নতুন কলাম হিসাব করবেন, সেগুলোর নাম কী দেবেন, টেক্সট কীভাবে জোড়া লাগাবেন, আর ডুপ্লিকেট সারি কীভাবে সরাবেন।
সারি বাছাই (WHERE) আর সাজানো (ORDER BY) নিয়ে সামনে আলাদা পাতা আছে। এখানে তবু প্রতিটা কোয়েরি শেষ হয় একটা ORDER BY দিয়ে, যাতে ফলাফল সবসময় একই ক্রমে আসে।
যা শিখবেন
SELECT *আর কলাম বাছাই- অঙ্ক আর এক্সপ্রেশন, পূর্ণসংখ্যার ভাগের ফাঁদ, আর হিসাবে NULL কী করে
ASদিয়ে ফলাফলের কলামের নাম দেওয়া- টেক্সট জোড়া: SQLite আর PostgreSQL-এ
||, MySQL-এCONCAT() - এক ও একাধিক কলামে
DISTINCT, আর কেনSELECT *ঘেঁটে দেখার জন্য ভালো কিন্তু কোডে খারাপ
SELECT *: সব কলাম
স্টার (*) মানে "সব কলাম, টেবিলে যে ক্রমে আছে সেই ক্রমে"। একটা টেবিলে কী আছে দেখার সবচেয়ে দ্রুত উপায়:
SELECT * FROM categories ORDER BY category_id;+-------------+-------------+
| category_id | name |
+-------------+-------------+
| 1 | Books |
| 2 | Electronics |
| 3 | Courses |
| 4 | Accessories |
| 5 | Furniture |
+-------------+-------------+বড় টেবিলে LIMIT জুড়ে দিন, যাতে লক্ষ লক্ষ সারি না টেনে কয়েকটা সারি দেখেন:
SELECT * FROM products ORDER BY product_id LIMIT 3;+------------+---------------------------+-------------+-------+-------+
| product_id | name | category_id | price | stock |
+------------+---------------------------+-------------+-------+-------+
| 1 | Python Crash Course | 1 | 1200 | 40 |
| 2 | Hands-On Machine Learning | 1 | 2500 | 15 |
| 3 | Mechanical Keyboard | 2 | 4500 | 12 |
+------------+---------------------------+-------------+-------+-------+কলাম বাছাই
যে কলামগুলো চান সেগুলোর নাম কমা দিয়ে আলাদা করে লিখুন। সেগুলো ফেরত আসে আপনার লেখা ক্রমে, টেবিলের ক্রমে নয়:
SELECT price, name
FROM products
ORDER BY product_id
LIMIT 5;+-------+---------------------------+
| price | name |
+-------+---------------------------+
| 1200 | Python Crash Course |
| 2500 | Hands-On Machine Learning |
| 4500 | Mechanical Keyboard |
| 900 | Wireless Mouse |
| 18500 | 27-inch Monitor |
+-------+---------------------------+কলাম বাছাই হলো ফিচার বাছাইয়ের SQL রূপ: কোন প্রোডাক্টের স্টক ফুরিয়ে যাবে, তা অনুমান করে এমন মডেলের দরকার price আর stock, প্রোডাক্টের নাম নয়।
এক্সপ্রেশন আর অঙ্ক
ফলাফলের একটা কলাম টেবিলে থাকতেই হবে এমন নয়। যেকোনো এক্সপ্রেশন চলে: + - * / আর % (ভাগশেষ) দিয়ে অঙ্ক, ধ্রুবক, ফাংশন। এই হলো প্রতিটা প্রোডাক্টের স্টকে আটকে থাকা টাকা:
SELECT product_id, name, price, stock, price * stock AS stock_value
FROM products
ORDER BY product_id;+------------+-----------------------------+-------+-------+-------------+
| product_id | name | price | stock | stock_value |
+------------+-----------------------------+-------+-------+-------------+
| 1 | Python Crash Course | 1200 | 40 | 48000 |
| 2 | Hands-On Machine Learning | 2500 | 15 | 37500 |
| 3 | Mechanical Keyboard | 4500 | 12 | 54000 |
| 4 | Wireless Mouse | 900 | 60 | 54000 |
| 5 | 27-inch Monitor | 18500 | 5 | 92500 |
| 6 | SQL Masterclass | 3000 | NULL | NULL |
| 7 | AI Engineering Bootcamp | 15000 | NULL | NULL |
| 8 | Laptop Stand | 1500 | 25 | 37500 |
| 9 | USB-C Hub | 2200 | 0 | 0 |
| 10 | Noise-Cancelling Headphones | 7500 | 8 | 60000 |
| 11 | Gift Card | 1000 | NULL | NULL |
+------------+-----------------------------+-------+-------+-------------+প্রোডাক্ট ৬, ৭ আর ১১ দেখুন। এদের stock হলো NULL (কোর্স আর গিফট কার্ড গোনা হয় না), তাই price * stock-ও NULL: NULL-এর সাথে যেকোনো অঙ্কের ফল NULL। সাধারণত এটাই ঠিক — "অজানা গুণ ৩০০০ অজানাই" — কিন্তু এর মানে একটা ফিচার কলাম NULL-এ ভরে যেতে পারে, যা পরে pandas পড়বে NaN হিসেবে। এগুলো কীভাবে বদলাবেন, দেখাবে টেক্সট, সংখ্যা ও তারিখের ফাংশন, CAST আর COALESCE পাতা।
পূর্ণসংখ্যার ভাগের ফাঁদ
SQLite, PostgreSQL আর SQL Server-এ দুটো পূর্ণসংখ্যা ভাগ করলে ফল হয় পূর্ণসংখ্যা, ভাগশেষ ফেলে দিয়ে। দশমিক উত্তর পেতে একটা দিককে দশমিক করে দিন:
SELECT name,
price,
price / 1000 AS thousands_wrong,
price / 1000.0 AS thousands,
ROUND(price * 1.15, 2) AS price_with_vat
FROM products
ORDER BY product_id
LIMIT 4;+---------------------------+-------+-----------------+-----------+----------------+
| name | price | thousands_wrong | thousands | price_with_vat |
+---------------------------+-------+-----------------+-----------+----------------+
| Python Crash Course | 1200 | 1 | 1.2 | 1380.0 |
| Hands-On Machine Learning | 2500 | 2 | 2.5 | 2875.0 |
| Mechanical Keyboard | 4500 | 4 | 4.5 | 5175.0 |
| Wireless Mouse | 900 | 0 | 0.9 | 1035.0 |
+---------------------------+-------+-----------------+-----------+----------------+প্রথম সূত্রে Wireless Mouse-এর দাম ০ হাজার টাকা। MySQL এখানে ব্যতিক্রম: এর / সবসময় দশমিক দেয় (900 / 1000 হলো 0.9000), তাই একই কোয়েরি ভিন্ন ডেটাবেসে ভিন্ন সংখ্যা দেয় — জেনেবুঝে 1000.0 লেখার আরেকটা কারণ। ROUND(x, 2) টাকার হিসাব দুই দশমিক ঘরে রাখে; দশমিকের পরে শুধু শূন্য থাকলে SQLite দেখায় 1380.0, PostgreSQL দেখায় 1380.00।
এক্সপ্রেশন যেকোনো কলামে চলে, তাই অর্ডারের প্রতিটা লাইনের আয় হলো সোজা পরিমাণ × একক দাম:
SELECT order_id, product_id, quantity, unit_price,
quantity * unit_price AS line_total
FROM order_items
WHERE order_id IN (7, 9)
ORDER BY order_id, product_id;+----------+------------+----------+------------+------------+
| order_id | product_id | quantity | unit_price | line_total |
+----------+------------+----------+------------+------------+
| 7 | 4 | 2 | 900 | 1800 |
| 7 | 9 | 1 | 2200 | 2200 |
| 9 | 3 | 1 | 4050 | 4050 |
| 9 | 4 | 1 | 900 | 900 |
+----------+------------+----------+------------+------------+টেবিল ছাড়াও SELECT করা যায়, SQL-কে ক্যালকুলেটর হিসেবে ব্যবহার করে — একটা এক্সপ্রেশন যাচাই করতে কাজের। অঙ্কের চেনা নিয়মই খাটে (+ আর --এর আগে * আর /):
SELECT 2 + 3 * 4 AS no_brackets, (2 + 3) * 4 AS with_brackets, 17 % 5 AS remainder;+-------------+---------------+-----------+
| no_brackets | with_brackets | remainder |
+-------------+---------------+-----------+
| 14 | 20 | 2 |
+-------------+---------------+-----------+AS দিয়ে কলামের নাম
নাম না দিলে হিসাব করা কলামের লেবেল হয় তার এক্সপ্রেশনটাই, যেমন price * stock — রিপোর্টে বেমানান, কোডে আরও খারাপ। AS একে একটা অ্যালিয়াস (ছদ্মনাম) দেয়। AS শব্দটা ঐচ্ছিক (price * stock stock_value-ও চলে), কিন্তু লিখুন: এতে অ্যালিয়াসটা চোখে পড়ে। স্পেস বা বড় হাতের অক্ষরওয়ালা অ্যালিয়াসে ডাবল কোট লাগে:
SELECT name AS product, price * stock AS "Stock value (taka)"
FROM products
WHERE stock > 0
ORDER BY product_id
LIMIT 3;+---------------------------+--------------------+
| product | Stock value (taka) |
+---------------------------+--------------------+
| Python Crash Course | 48000 |
| Hands-On Machine Learning | 37500 |
| Mechanical Keyboard | 54000 |
+---------------------------+--------------------+কোড যা পড়বে, তার জন্য snake_case অ্যালিয়াসই ভালো: এগুলোই আপনার DataFrame-এর কলামের নাম হয়, আর df["Stock value (taka)"]-এর চেয়ে df["stock_value"] লেখা সহজ:
import pandas as pd
from sqlhelp import con
df = pd.read_sql("""
SELECT product_id, price, stock, price * stock AS stock_value
FROM products
ORDER BY product_id
""", con)
print(list(df.columns))
print(df["stock_value"].sum())['product_id', 'price', 'stock', 'stock_value']
383500.0যোগ করার সময় pandas তিনটা NULL (NaN) বাদ দিয়েছে, এ জন্যই মোটটা float। মনে রাখবেন, অ্যালিয়াসের জন্ম SELECT ধাপে, তাই সেটা দিয়ে সাজাতে পারবেন, কিন্তু WHERE-এ ফিল্টার করতে পারবেন না (দেখুন SQL কীভাবে কাজ করে: স্টেটমেন্ট, কমান্ডের ধরন আর কোয়েরির ক্রম)।
টেক্সট জোড়া লাগানো
স্ট্যান্ডার্ড SQL স্ট্রিং জোড়ে || দিয়ে। SQLite আর PostgreSQL এটা মানে; সংখ্যা নিজে থেকেই টেক্সটে বদলে যায়:
SELECT 'Order #' || order_id || ' (' || status || ')' AS label
FROM orders
WHERE customer_id = 2
ORDER BY order_id;+----------------------+
| label |
+----------------------+
| Order #2 (delivered) |
| Order #6 (delivered) |
| Order #12 (shipped) |
+----------------------+ডেটাবেসভেদে দুটো জিনিস গোলমাল করে। প্রথমত, NULL পুরো স্ট্রিংটাই গিলে ফেলে: কাস্টমার ৫-এর শহর নেই, তাই name || ' (' || city || ')' হয় NULL। দ্বিতীয়ত, MySQL ||-কে পড়ে লজিক্যাল OR হিসেবে (একটা ডেপ্রিকেটেড ফিচার, যদি না সার্ভার PIPES_AS_CONCAT মোডে চলে), তাই সেখানে CONCAT() ব্যবহার করতেই হবে। একই দুজন কাস্টমারের ওপর তিনটা ডেটাবেস দেখুন:
SELECT name || ' (' || city || ')' AS piped,
CONCAT(name, ' (', city, ')') AS concat_fn
FROM customers
WHERE customer_id IN (1, 5)
ORDER BY customer_id;+----------------------+----------------------+
| piped | concat_fn |
+----------------------+----------------------+
| Nadia Rahman (Dhaka) | Nadia Rahman (Dhaka) |
| NULL | Sadia Chowdhury () |
+----------------------+----------------------+-- PostgreSQL
SELECT name || ' (' || city || ')' AS piped,
CONCAT(name, ' (', city, ')') AS concat_fn
FROM customers
WHERE customer_id IN (1, 5)
ORDER BY customer_id;+----------------------+----------------------+
| piped | concat_fn |
+----------------------+----------------------+
| Nadia Rahman (Dhaka) | Nadia Rahman (Dhaka) |
| NULL | Sadia Chowdhury () |
+----------------------+----------------------+-- MySQL
SELECT name || ' (' || city || ')' AS piped,
CONCAT(name, ' (', city, ')') AS concat_fn
FROM customers
WHERE customer_id IN (1, 5)
ORDER BY customer_id;+-------+----------------------+
| piped | concat_fn |
+-------+----------------------+
| 0 | Nadia Rahman (Dhaka) |
| NULL | NULL |
+-------+----------------------+| ডেটাবেস | || | NULL আর্গুমেন্টসহ CONCAT() |
|---|---|---|
| SQLite | টেক্সট জোড়ে; NULL থাকলে ফল NULL | NULL-কে ফাঁকা টেক্সট ধরে (SQLite 3.44+ লাগবে) |
| PostgreSQL | টেক্সট জোড়ে; NULL থাকলে ফল NULL | NULL-কে ফাঁকা টেক্সট ধরে |
| MySQL | লজিক্যাল OR: টেক্সট নয়, 0 বা NULL | NULL ফেরত দেয় (CONCAT_WS ব্যবহার করুন, যা NULL বাদ দেয়) |
| SQL Server | প্রচলিতভাবে +; শুধু SQL Server 2025 আর Azure SQL ||-ও মানে | NULL-কে ফাঁকা টেক্সট ধরে |
AI-এর কাজে কনক্যাটেনেশন দিয়েই সেই টেক্সট বানানো হয়, যা এমবেডিং মডেলে পাঠাবেন বা প্রম্পটে বসাবেন: প্রতিটা প্রোডাক্ট বা সাপোর্ট টিকিটের জন্য কয়েকটা কলাম মিলিয়ে একটা স্ট্রিং। এক কলামের একটা NULL যেন পুরো টেক্সটটা চুপচাপ মুছে না দেয় — সেটা যাচাই করুন।
DISTINCT: ডুপ্লিকেট সারি সরানো
DISTINCT প্রতিটা আলাদা ফলাফল-সারির একটা করে কপি রাখে। কাস্টমাররা কোন কোন শহরের?
SELECT DISTINCT city FROM customers ORDER BY city;+------------+
| city |
+------------+
| NULL |
| Chattogram |
| Dhaka |
| Khulna |
| Rajshahi |
| Sylhet |
+------------+৮ জন কাস্টমার, ৬টা আলাদা মান। DISTINCT সব NULL-কে একটাই মান ধরে, তাই না-থাকা শহরটা আসে একবার। (SQLite আর MySQL NULL-কে সাজায় সবার আগে; PostgreSQL সবার শেষে — সাজানো আর পেজিং: ORDER BY, LIMIT ও OFFSET পাতায় এটা আছে।)
একাধিক কলামে DISTINCT দেখে পুরো সারিটা, অর্থাৎ মানগুলোর জোড়া। ১৪টা অর্ডারের মধ্যে কোন কোন কাস্টমার–স্ট্যাটাস জোড়া আছে?
SELECT DISTINCT customer_id, status
FROM orders
ORDER BY customer_id, status;+-------------+-----------+
| customer_id | status |
+-------------+-----------+
| 1 | delivered |
| 2 | delivered |
| 2 | shipped |
| 3 | delivered |
| 4 | cancelled |
| 5 | delivered |
| 6 | delivered |
| 6 | pending |
| 7 | delivered |
+-------------+-----------+কাস্টমার ২ দুবার এসেছেন, কারণ তাঁর delivered আর shipped দুই ধরনের অর্ডারই আছে; কাস্টমার ১-এর তিনটা delivered অর্ডার মিলে একটা সারি। আলাদা মান গুনতে হলে DISTINCT বসান COUNT-এর ভেতরে (অ্যাগ্রিগেট নিয়ে আলাদা পাতা আছে, অ্যাগ্রিগেট, GROUP BY ও HAVING):
SELECT COUNT(*) AS orders, COUNT(DISTINCT customer_id) AS customers_who_ordered
FROM orders;+--------+-----------------------+
| orders | customers_who_ordered |
+--------+-----------------------+
| 14 | 7 |
+--------+-----------------------+৮ জনের মধ্যে ৭ জন কাস্টমার অর্ডার দিয়েছেন; বাকি জনকে খুঁজে বের করবেন LEFT, RIGHT, FULL, CROSS আর সেলফ জয়েন পাতায়, একটা LEFT JOIN দিয়ে। DISTINCT বিনা খরচে হয় না — ডুপ্লিকেট খুঁজতে ডেটাবেসকে প্রতিটা সারি সাজাতে বা হ্যাশ করতে হয় — আর অপ্রত্যাশিত ডুপ্লিকেটের সমাধান এটা কখনোই নয়। কোয়েরি বারবার একই সারি ফেরত দিলে কারণটা খুঁজুন (সাধারণত একটা জয়েন, দেখুন অনেক টেবিল জয়েন, আর ডুপ্লিকেট সারির ফাঁদ), লুকিয়ে ফেলবেন না।
SELECT * ঘেঁটে দেখার জন্য, কোডের জন্য নয়
শেল বা DB Browser-এ বসে একটা টেবিল দেখতে চাইলে SELECT * চমৎকার। কিন্তু প্রোগ্রামের ভেতরে এটা একটা টাইম বোমা, কারণ প্রোগ্রামটা চুপচাপ ধরে নেয় টেবিলে ঠিক এই কলামগুলো, ঠিক এই ক্রমে আছে। একজন সহকর্মী একটা কলাম যোগ করলে কী হয় দেখুন:
from sqlhelp import con
def product_cards():
rows = con.execute("SELECT * FROM products WHERE product_id <= 2 ORDER BY product_id").fetchall()
for product_id, name, category_id, price, stock in rows:
print(f"{product_id}: {name} costs {price}")
product_cards()
con.execute("ALTER TABLE products ADD COLUMN description TEXT") # নতুন একটা কলাম হাজির
con.commit()
try:
product_cards()
except ValueError as error:
print("ValueError:", error)1: Python Crash Course costs 1200
2: Hands-On Machine Learning costs 2500
ValueError: too many values to unpack (expected 5)একই ফাংশন, কোনো বদল ছাড়াই, এখন ক্র্যাশ করছে। কলামের নাম লিখে দিলে নতুন কলামে আর কিছু যায় আসে না:
def product_cards():
rows = con.execute(
"SELECT product_id, name, price FROM products WHERE product_id <= 2 ORDER BY product_id"
).fetchall()
for product_id, name, price in rows:
print(f"{product_id}: {name} costs {price}")
product_cards()1: Python Crash Course costs 1200
2: Hands-On Machine Learning costs 2500কোডে কলামের নাম লেখার আরও কারণ: SELECT * অদরকারি কলামও টেনে আনে — AI অ্যাপে সেটা হতে পারে প্রতিটা সারির ১৫৩৬ সংখ্যার একটা এমবেডিং বা লম্বা একটা ডকুমেন্ট, যা নেটওয়ার্কে পাঠানো ডেটা কয়েক গুণ বাড়িয়ে দেয়; কোড আসলে কী ব্যবহার করছে তা লুকিয়ে রাখে; আর জয়েনের পর একই নামের দুটো কলাম ফেরত দিতে পারে। মোটা দাগের নিয়ম: হাতে চালানো কোয়েরিতে SELECT *, কোডের ফাইলে কলামের নাম।
সাধারণ ভুল
- একটা কমা বাদ পড়া।
SELECT name priceবৈধ SQL: এর মানেname AS price। কোনো এরর নেই, শুধুpriceনামের একটা কলাম, যা নামে ভরা:SELECT name price FROM products ORDER BY product_id LIMIT 3;সমাধান:+---------------------------+ | price | +---------------------------+ | Python Crash Course | | Hands-On Machine Learning | | Mechanical Keyboard | +---------------------------+SELECT name, price। ফলাফল অদ্ভুত দেখালে আগে কমাগুলো গুনুন। - পূর্ণসংখ্যার ভাগ। SQLite আর PostgreSQL-এ মাউসের জন্য
price / 1000হলো 0। সমাধান: ওপরের মতো1000.0দিয়ে ভাগ করুন। - MySQL-এ
||, বা||-এর ভেতরে NULL। MySQL-এCONCAT()ব্যবহার করুন; আর সব জায়গায় স্ট্রিং জোড়ার আগে ঠিক করুন না-থাকা মান কী হবে (COALESCE(city, 'unknown')— দেখুন টেক্সট, সংখ্যা ও তারিখের ফাংশন, CAST আর COALESCE):SELECT name || ' (' || COALESCE(city, 'unknown') || ')' AS label FROM customers WHERE customer_id IN (1, 5) ORDER BY customer_id;+---------------------------+ | label | +---------------------------+ | Nadia Rahman (Dhaka) | | Sadia Chowdhury (unknown) | +---------------------------+ - ভাবা যে
DISTINCTশুধু একটা কলামে খাটে।SELECT DISTINCT city, nameসারি সরায় কেবল তখনই, যখন শহর আর নাম দুটোই মেলে, তাই এটা ৮ জন কাস্টমারকেই ফেরত দেয়।DISTINCTসবসময় বাছাই করা পুরো সারিতে খাটে।
নিজে চেষ্টা করুন
- সহজ:
product_id১ থেকে ৪-এর প্রোডাক্টগুলোর জন্যname,price, আর ১৫% ভ্যাটসহ দাম দেখান — দুই দশমিক ঘরে রাউন্ড করা, নামprice_with_vat(ORDER BY product_id LIMIT 4ব্যবহার করুন)। - মাঝারি: ব্যবহৃত আলাদা আলাদা পেমেন্ট পদ্ধতিগুলো বর্ণানুক্রমে দেখান। তারপর ২০২৬-এর জানুয়ারি বা ফেব্রুয়ারিতে হওয়া পেমেন্টগুলোর (
WHERE paid_on < '2026-03-01') আলাদা আলাদা(method, paid_on)জোড়া দেখান। - কঠিন: একটা এমবেডিং মডেলের জন্য প্রতিটা প্রোডাক্টের এক লাইনের টেক্সট বানান, যেমন
Laptop Stand | price 1500 taka | stock 25, প্রোডাক্ট ৫ থেকে ৮-এর জন্য। কোর্সগুলোর স্টক NULL: সেগুলোর জন্য দেখানstock n/a(COALESCEব্যবহার করুন)। প্রথমে SQLite-এর জন্য লিখুন, তারপর PostgreSQL-এর জন্য, যেখানেCOALESCE-এর দুটো মানই টেক্সট হতে হবে (stock::text)।
উত্তর
১. ১.১৫ দিয়ে গুণ করে রাউন্ড করুন:
SELECT name, price, ROUND(price * 1.15, 2) AS price_with_vat
FROM products
ORDER BY product_id
LIMIT 4;+---------------------------+-------+----------------+
| name | price | price_with_vat |
+---------------------------+-------+----------------+
| Python Crash Course | 1200 | 1380.0 |
| Hands-On Machine Learning | 2500 | 2875.0 |
| Mechanical Keyboard | 4500 | 5175.0 |
| Wireless Mouse | 900 | 1035.0 |
+---------------------------+-------+----------------+২. প্রথমে এক কলামে DISTINCT, তারপর একটা জোড়ায়:
SELECT DISTINCT method FROM payments ORDER BY method;
SELECT DISTINCT method, paid_on
FROM payments
WHERE paid_on < '2026-03-01'
ORDER BY method, paid_on;+--------+
| method |
+--------+
| bkash |
| card |
| cash |
+--------+
+--------+------------+
| method | paid_on |
+--------+------------+
| bkash | 2026-01-12 |
| bkash | 2026-02-03 |
| card | 2026-01-20 |
| cash | 2026-02-16 |
+--------+------------+৩. SQLite-এ || সংখ্যাকে টেক্সটে বদলায়, আর COALESCE-এ সংখ্যা আর টেক্সট মেশানো যায়:
SELECT product_id,
name || ' | price ' || price || ' taka | stock ' || COALESCE(stock, 'n/a') AS embedding_text
FROM products
WHERE product_id BETWEEN 5 AND 8
ORDER BY product_id;+------------+--------------------------------------------------------+
| product_id | embedding_text |
+------------+--------------------------------------------------------+
| 5 | 27-inch Monitor | price 18500 taka | stock 5 |
| 6 | SQL Masterclass | price 3000 taka | stock n/a |
| 7 | AI Engineering Bootcamp | price 15000 taka | stock n/a |
| 8 | Laptop Stand | price 1500 taka | stock 25 |
+------------+--------------------------------------------------------+PostgreSQL টাইপের ব্যাপারে কড়া, তাই আগে stock-কে টেক্সটে কাস্ট করুন:
-- PostgreSQL
SELECT product_id,
name || ' | price ' || price || ' taka | stock ' || COALESCE(stock::text, 'n/a') AS embedding_text
FROM products
WHERE product_id BETWEEN 5 AND 8
ORDER BY product_id;+------------+--------------------------------------------------------+
| product_id | embedding_text |
+------------+--------------------------------------------------------+
| 5 | 27-inch Monitor | price 18500 taka | stock 5 |
| 6 | SQL Masterclass | price 3000 taka | stock n/a |
| 7 | AI Engineering Bootcamp | price 15000 taka | stock n/a |
| 8 | Laptop Stand | price 1500 taka | stock 25 |
+------------+--------------------------------------------------------+সারসংক্ষেপ
SELECT *সব কলাম ফেরত দেয়; কলাম বাছতে আর তাদের ক্রম ঠিক করতে নাম ধরে লিখুন।- যেকোনো এক্সপ্রেশন ফলাফলের কলাম হতে পারে। NULL-এর সাথে অঙ্কের ফল NULL; MySQL ছাড়া সব জায়গায় পূর্ণসংখ্যার ভাগ ভাগশেষ ফেলে দেয়, তাই
1000.0দিয়ে ভাগ করুন। ASকলামের নাম দেয়; কোড যা পড়বে তার জন্যsnake_case, ডাবল কোট শুধু দেখানোর নামের জন্য।- SQLite আর PostgreSQL-এ টেক্সট জুড়ুন
||দিয়ে, MySQL-এCONCAT()দিয়ে; NULL থাকলে||(আর MySQL-এরCONCAT) হয়ে যায় NULL। DISTINCTডুপ্লিকেট সারি সরায় — বাছাই করা সব কলাম মিলিয়ে — আর সব NULL-কে সমান ধরে;COUNT(DISTINCT col)আলাদা মানগুলো গোনে।- হাতে চালানো কোয়েরিতে
SELECT *, কোডে কলামের নাম।
এরপর: সাজানো আর পেজিং: ORDER BY, LIMIT ও OFFSET পাতায় বুঝবেন সেই ORDER BY আর LIMIT, যা এতদিন প্রতিটা কোয়েরিতে ব্যবহার করে আসছেন: একাধিক কলাম আর এক্সপ্রেশন ধরে সাজানো, NULL কোথায় যায়, সেরা-N তালিকা, আর পেজিং করে ফলাফল দেখা।