অধ্যায় 3 · ডেটা তৈরি ও বদলানো
ডেটা টাইপ, NULL আর ঠিক টাইপ বাছাই
- পৃষ্ঠা 10 / 22
- 13 মিনিট পড়া
প্রতিটা কলামের একটা ডেটা টাইপ থাকে: পূর্ণসংখ্যা, দশমিক, টেক্সট, তারিখ, সত্য/মিথ্যা। টাইপ ঠিক করে কলামটা কোন মান নেবে, সেগুলো কীভাবে তুলনা হবে আর সাজবে, কতটা জায়গা নেবে, আর পাটিগণিত সেগুলো নিয়ে কী করবে। টাইপ থেকে আসা বাগ গত কয়েক পাতায় দেখেছেন: '9' < '10' মিথ্যা, 7 / 2 সমান ৩, দামের কলামে বসে থাকা cheap শব্দটা।
টাইপ এক জায়গা থেকে আরেক জায়গায় যায়ও। টেবিল pandas-এ লোড করলে কলামের টাইপ হয়ে যায় dtype; পাইপলাইন ফিচারগুলো Parquet-এ লিখলে হয়ে যায় Parquet টাইপ; মডেল যখন পড়ে, টেক্সট হিসেবে রাখা তারিখ তার কাছে স্রেফ একটা স্ট্রিং, যা থেকে সে কিছু শিখতে পারে না। ডেটাবেসেই ঠিকঠাক টাইপ বেছে নেওয়া হলো ডেটা পরিষ্কারের সবচেয়ে সস্তা উপায়।
যা শিখবেন
- সংখ্যা: পূর্ণসংখ্যা, নিখুঁত দশমিক আর ফ্লোটিং পয়েন্ট, আর টাকার হিসাব কেন কখনো FLOAT নয়।
- টেক্সট:
CHAR,VARCHARআরTEXT, আর দৈর্ঘ্যের সীমা আসলে কী করে। - তারিখ ও সময়: SQLite-এ ISO 8601 টেক্সট, অন্যত্র
DATE/TIMESTAMP/TIMESTAMPTZ, আর টাইম জোন। - তিন ডেটাবেসে বুলিয়ান, আর NULL, অর্থাৎ কোনো মানই না থাকা।
- SQLite-এর টাইপ অ্যাফিনিটি, STRICT টেবিল, আর টাইপ বাছাইয়ের একটা টেবিল।
SQLite পাঁচ রকমের মান রাখে
SQLite সবার থেকে আলাদা, তাই শুরু সেখান থেকেই। কলাম যে টাইপেই ঘোষিত হোক, SQLite প্রতিটা মান রাখে পাঁচটা স্টোরেজ ক্লাসের একটায়, আর কোনটায়, তা বলে দেয় typeof():
SELECT typeof(42), typeof(4.2), typeof('42'), typeof(NULL), typeof(x'2A');+------------+-------------+--------------+--------------+---------------+
| typeof(42) | typeof(4.2) | typeof('42') | typeof(NULL) | typeof(x'2A') |
+------------+-------------+--------------+--------------+---------------+
| integer | real | text | null | blob |
+------------+-------------+--------------+--------------+---------------+INTEGER, REAL (ফ্লোটিং-পয়েন্ট সংখ্যা), TEXT, NULL আর BLOB (কাঁচা বাইট, যেমন একটা ছবি বা সিরিয়ালাইজ করা এমবেডিং)। তারিখ, দশমিক বা বুলিয়ানের আলাদা কোনো স্টোরেজ নেই। MySQL আর PostgreSQL আলাদা: সেখানে কলামের টাইপ খাটানো হয়, আর যে মান মানায় না তা ফিরিয়ে দেওয়া হয়। পাতার বাকি অংশে এই পার্থক্যটা মাথায় রাখুন।
সংখ্যা: পূর্ণসংখ্যা, দশমিক, ফ্লোট
| ধরন | SQLite | MySQL | PostgreSQL | কীসের জন্য |
|---|---|---|---|---|
| পূর্ণসংখ্যা | INTEGER (৮ বাইট পর্যন্ত) | INT, BIGINT | INTEGER, BIGINT | id, গণনা, পরিমাণ, সবচেয়ে ছোট এককে টাকা |
| নিখুঁত দশমিক | নেই (NUMERIC অ্যাফিনিটি, রাখা হয় int বা real হিসেবে) | DECIMAL(p, s) | NUMERIC(p, s) / DECIMAL | টাকা, যা কিছু হুবহু মিলতে হবে |
| ফ্লোটিং পয়েন্ট | REAL (৮ বাইট) | FLOAT, DOUBLE | REAL (৪ বাইট), DOUBLE PRECISION | পরিমাপ, স্কোর, সম্ভাবনা, ML ফিচার |
DECIMAL(10, 2) মানে মোট ১০টা অঙ্ক পর্যন্ত, যার ২টা দশমিক বিন্দুর পরে: সবচেয়ে বড় মান 99,999,999.99। PostgreSQL-এর INTEGER থামে 2,147,483,647-এ, প্রায় ২১৪ কোটি, যা ব্যস্ত একটা টেবিলের id বা LLM টোকেনের যোগফল সহজেই পেরিয়ে যেতে পারে:
-- PostgreSQL
SELECT 2147483647 + 1 AS too_big;Error: integer out of rangeBIGINT যায় প্রায় 9.2 × 10¹⁸ পর্যন্ত। যে টেবিল সীমাহীনভাবে বাড়ে (ইভেন্ট, লগ, মেসেজ), তার id আর চলমান যোগফলের জন্য এটা ব্যবহার করুন। SQLite-এর INTEGER এমনিতেই ৮ বাইট, তাই সেখানে এই সমস্যা নেই।
টাকার হিসাব কেন কখনো FLOAT নয়
ফ্লোটিং-পয়েন্ট সংখ্যা রাখা হয় বাইনারিতে, আর 0.1-এর মতো বেশিরভাগ দশমিক ভগ্নাংশের কোনো নিখুঁত বাইনারি রূপ নেই। ভুলগুলো খুব ছোট, কিন্তু আছে:
SELECT 0.1 + 0.2 AS total, 0.1 + 0.2 = 0.3 AS equal;+---------------------+-------+
| total | equal |
+---------------------+-------+
| 0.30000000000000004 | 0 |
+---------------------+-------+sqlite3 শেল দেখানোর সময় ১৫ অঙ্কে গোল করে 0.3 প্রিন্ট করে, কিন্তু equal কলাম আসল কথাটা ফাঁস করে দেয়। PostgreSQL আর MySQL-এ 0.1-এর মতো লিটারাল ডিফল্টভাবে নিখুঁত দশমিক, আর বাইনারি ফ্লোটিং পয়েন্ট হয় কেবল আপনি চাইলে। পাশাপাশি দেখুন:
-- PostgreSQL
SELECT 0.1 + 0.2 AS numeric_sum,
0.1::float8 + 0.2::float8 AS float_sum;+-------------+---------------------+
| numeric_sum | float_sum |
+-------------+---------------------+
| 0.3 | 0.30000000000000004 |
+-------------+---------------------+এক পয়সার ভগ্নাংশের গোলমাল নিরীহই মনে হয়, যতক্ষণ না দশ লাখ পেমেন্ট যোগ করা মাসিক রিপোর্ট কয়েক টাকা গরমিল দেখায় আর হিসাবরক্ষক জানতে চান কেন। টাকা রাখার দুটো নির্ভরযোগ্য উপায়:
- সবচেয়ে ছোট এককে পূর্ণসংখ্যা: ১৯.৯৯ টাকা নয়, ১৯৯৯ পয়সা। SQLite-সহ সব ডেটাবেসে নিখুঁত। BitByte Shop দাম রাখে পূর্ণ টাকায়, যা একই ধারণা।
DECIMAL(12, 2)(PostgreSQL-এNUMERIC): MySQL আর PostgreSQL-এ নিখুঁত দশমিক হিসাব। Python এগুলো পায়floatহিসেবে নয়,decimal.Decimalহিসেবে।
যা গোনা হয় না, মাপা হয়, তার জন্য ফ্লোটই ঠিক: মডেলের কনফিডেন্স স্কোর, মিলিসেকেন্ডে লেটেন্সি, ০–১-এ স্কেল করা ফিচার, এমবেডিংয়ের সংখ্যাগুলো। শুধু কখনো = দিয়ে পরীক্ষা করবেন না; একটা সহনসীমা (tolerance) দিয়ে তুলনা করুন, বা আগে গোল করে নিন।
টেক্সট: CHAR, VARCHAR, TEXT
CHAR(n): ঠিক nটা অক্ষর, বাকিটা স্পেস দিয়ে ভরা। শুধু নির্দিষ্ট দৈর্ঘ্যের কোডের জন্য কাজের, যেমনCHAR(2)দেশের কোড বাCHAR(3)মুদ্রার কোড।VARCHAR(n): nটা অক্ষর পর্যন্ত। নাম, ইমেইল আর স্ট্যাটাসের জন্য সাধারণ পছন্দ; সীমাটা জানিয়ে দেয় আপনি কী আশা করছেন, আর উল্টোপাল্টা মান আটকায়।TEXT: যেকোনো দৈর্ঘ্য। বিবরণ, প্রম্পট, মডেলের উত্তর, ডকুমেন্টের জন্য। PostgreSQL-এTEXTআরVARCHAR-এর পারফরম্যান্স একই।
দৈর্ঘ্যের সীমাতেই SQLite আলাদা। সে ঘোষণাটা মেনে নেয় আর সংখ্যাটা উপেক্ষা করে:
CREATE TABLE short_names (name VARCHAR(5));
INSERT INTO short_names VALUES ('Farhana Akter');
SELECT name, length(name) AS characters FROM short_names;
DROP TABLE short_names;+---------------+------------+
| name | characters |
+---------------+------------+
| Farhana Akter | 13 |
+---------------+------------+-- PostgreSQL
CREATE TABLE short_names (name VARCHAR(5));
INSERT INTO short_names VALUES ('Farhana Akter');Error: value too long for type character varying(5)strict মোডে MySQL বলে ERROR 1406: Data too long for column 'name' at row 1। দুই সার্ভারেই n গোনে অক্ষর, বাইট নয়; তাই "ফারহানা"-র মতো বাংলা নাম ২১ বাইট নয়, ৭টা অক্ষর ধরা হয়। MySQL-এ utf8mb4 ক্যারেক্টার সেট ব্যবহার করুন (8.0 থেকে ডিফল্ট): পুরোনো utf8 ইমোজি আর আরও কিছু অক্ষর রাখতে পারে না, ব্যবহারকারীর লেখা টেক্সট ইনসার্ট ব্যর্থ হওয়ার এটা একটা চিরচেনা কারণ।
তারিখ ও সময়
| প্রয়োজন | SQLite | MySQL | PostgreSQL |
|---|---|---|---|
| ক্যালেন্ডারের একটা তারিখ | TEXT '2026-03-08' | DATE | DATE |
| তারিখ আর সময় | TEXT '2026-03-08 10:00:00' | DATETIME | TIMESTAMP |
| সময়ের একটা নির্দিষ্ট মুহূর্ত, টাইম জোনসহ | UTC-তে TEXT, যেমন '2026-03-08T04:00:00Z' | TIMESTAMP (UTC-তে রাখা, ১৯৭০–২০৩৮ সাল) | TIMESTAMPTZ |
SQLite-এ তারিখের কোনো টাইপ নেই। তারিখ হলো ISO 8601 রূপের টেক্সট (কিছু অ্যাপ এর বদলে Unix-epoch পূর্ণসংখ্যা ব্যবহার করে), আর SQLite-এর তারিখের ফাংশনগুলো এই টেক্সট বোঝে:
SELECT order_date,
typeof(order_date) AS stored_as,
date(order_date, '+30 days') AS due_date
FROM orders
WHERE order_id = 1;+------------+-----------+------------+
| order_date | stored_as | due_date |
+------------+-----------+------------+
| 2026-01-12 | text | 2026-02-11 |
+------------+-----------+------------+এটা কাজ করে কেবল তখনই, যখন প্রতিটা মান একই ISO রূপে লেখা। '12/01/2026' হিসেবে লেখা একটা সারি সেই সারির জন্য সাজানো, রেঞ্জ ফিল্টার আর তারিখের ফাংশন নীরবে ভেঙে দেয়।
টাইম জোন
বাংলাদেশ UTC+6, আপনার ক্লাউড সার্ভার সম্ভবত UTC-তে, আর ব্যবহারকারীরা যেকোনো জায়গায় থাকতে পারেন। PostgreSQL-এর TIMESTAMPTZ একটা নিখুঁত মুহূর্ত রাখে (ভেতরে UTC-তে) আর দেখায় সেশনের টাইম জোনে। জোন ছাড়া TIMESTAMP ঘড়ির কাঁটা যা দেখিয়েছিল তা-ই রাখে, কোথাকার ঘড়ি তা না জেনে:
-- PostgreSQL
SELECT TIMESTAMPTZ '2026-03-08 10:00:00+06' AS instant,
TIMESTAMP '2026-03-08 10:00:00' AS wall_clock;+---------------------------+---------------------+
| instant | wall_clock |
+---------------------------+---------------------+
| 2026-03-08 04:00:00+00:00 | 2026-03-08 10:00:00 |
+---------------------------+---------------------+ঢাকার সকাল ১০টা মানে UTC-র ভোর ৪টা; এই সেশন UTC-তে চলছে, তাই সেভাবেই দেখানো হয়েছে। সেশনকে ঢাকার সময়ে নিলে একই মুহূর্ত স্থানীয়ভাবে দেখায়:
-- PostgreSQL
SET TIME ZONE 'Asia/Dhaka';
SELECT TIMESTAMPTZ '2026-03-08 04:00:00+00' AS same_instant;+---------------------------+
| same_instant |
+---------------------------+
| 2026-03-08 10:00:00+06:00 |
+---------------------------+(এই টেবিলগুলো Python প্রিন্ট করেছে, যা অফসেট লেখে +06:00; psql লেখে +06।) যে নিয়ম আপনাকে বাঁচাবে: মুহূর্তগুলো টাইম-জোন-সচেতন টাইপে UTC-তে রাখুন, স্থানীয় সময়ে বদলান শুধু দেখানোর সময়। AI-এর কাজেও এটা জরুরি: "দৈনিক সক্রিয় ব্যবহারকারী" বা "দিনে কতগুলো কল" UTC-তে গুনলে ঢাকার সময় মধ্যরাত থেকে সকাল ৬টা পর্যন্ত সবকিছু আগের দিনে পড়ে যায়।
বুলিয়ান
SQLite-এ বুলিয়ান টাইপ নেই: TRUE আর FALSE স্রেফ পূর্ণসংখ্যা ১ আর ০। MySQL-ও ১ আর ০ দেখায়, আর তার BOOLEAN আসলে একটা ছোট পূর্ণসংখ্যার আরেক নাম:
-- MySQL
CREATE TABLE flags (is_active BOOLEAN, price DECIMAL(10, 2), score FLOAT);
SELECT column_name, column_type
FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'flags'
ORDER BY ordinal_position;+-------------+---------------+
| COLUMN_NAME | COLUMN_TYPE |
+-------------+---------------+
| is_active | tinyint(1) |
| price | decimal(10,2) |
| score | float |
+-------------+---------------+সত্যিকারের BOOLEAN টাইপ, true আর false-সহ, আছে শুধু PostgreSQL-এ, যেমনটা দেখেছেন সারি বাছাই: WHERE, AND, OR ও NOT পাতায়। সব ডেটাবেসে খাটে এমন পরামর্শ: ফ্ল্যাগ কলামের নাম প্রশ্নের মতো রাখুন (is_active, has_paid), রাখুন 0/1 বা BOOLEAN, আর ফিল্টার করুন SQLite ও MySQL-এ WHERE is_active = 1 দিয়ে, PostgreSQL-এ WHERE is_active দিয়ে।
NULL শূন্যও নয়, খালিও নয়
কলাম NOT NULL ঘোষিত না হলে যেকোনো টাইপের কলামেই NULL থাকতে পারে। এটা অনুপস্থিত মান, যা ০ বা খালি স্ট্রিং থেকে আলাদা:
SELECT '' IS NULL AS empty_is_null,
0 IS NULL AS zero_is_null,
length('') AS empty_length,
length(NULL) AS null_length;+---------------+--------------+--------------+-------------+
| empty_is_null | zero_is_null | empty_length | null_length |
+---------------+--------------+--------------+-------------+
| 0 | 0 | 0 | NULL |
+---------------+--------------+--------------+-------------+প্রতিটা কলামের জন্য "অনুপস্থিত"-এর একটাই রূপ ঠিক করুন আর সবসময় সেটাই মেনে চলুন। যে কলামে কিছু অনুপস্থিত ইমেইল NULL আর কিছু '', তার প্রতিটা কোয়েরিতে দুটো যাচাই লাগে, আর কেউ না কেউ একটা ভুলে যাবেই। (Oracle ব্যতিক্রমীভাবে ''-কে NULL ধরে, যা সেখান থেকে আসা মানুষদের অবাক করে।)
SQLite-এর টাইপ অ্যাফিনিটি, আর STRICT টেবিল
SQLite-এ ঘোষিত টাইপ একটা পছন্দ মাত্র, যাকে বলে কলামের অ্যাফিনিটি। এটা বাছা হয় টাইপের নাম দেখে: নামে INT থাকলে INTEGER অ্যাফিনিটি; CHAR, CLOB বা TEXT থাকলে TEXT; REAL, FLOA বা DOUB থাকলে REAL; DATE আর DECIMAL-সহ বাকি বেশিরভাগ নামে NUMERIC। কোনো তথ্য না হারিয়ে মানটাকে পছন্দের টাইপে বদলানো গেলে SQLite বদলে নেয়, না গেলে যেমন আছে তেমনই রাখে:
CREATE TABLE affinity_demo (n INTEGER, t TEXT, r REAL);
INSERT INTO affinity_demo VALUES ('42', 42, '3'), ('abc', 4.5, 'x'), (7.0, '007', 2);
SELECT n, typeof(n), t, typeof(t), r, typeof(r) FROM affinity_demo;+-----+-----------+-----+-----------+-----+-----------+
| n | typeof(n) | t | typeof(t) | r | typeof(r) |
+-----+-----------+-----+-----------+-----+-----------+
| 42 | integer | 42 | text | 3.0 | real |
| abc | text | 4.5 | text | x | text |
| 7 | integer | 007 | text | 2.0 | real |
+-----+-----------+-----+-----------+-----+-----------+'42' হয়ে গেছে পূর্ণসংখ্যা 42, আর 7.0 হয়েছে 7, কিন্তু 'abc' বদলানো যায়নি, তাই একটা INTEGER কলামে সেটা টেক্সট হিসেবেই রয়ে গেছে। এই নমনীয়তার কারণেই আগের পাতায় দামের ঘরে cheap ঢুকে পড়েছিল। SQLite 3.37 থেকে টেবিলের শেষে STRICT যোগ করে এটা বন্ধ করা যায়:
CREATE TABLE strict_demo (n INTEGER, t TEXT) STRICT;
INSERT INTO strict_demo VALUES ('42', 'ok'); -- তবুও বদলায়: '42' স্পষ্টতই 42
INSERT INTO strict_demo VALUES ('abc', 'bad'); -- ফিরিয়ে দেওয়া হয়Error: cannot store TEXT value in INTEGER column strict_demo.nSTRICT টেবিল শুধু INT, INTEGER, REAL, TEXT, BLOB আর ANY টাইপ মানে, তাই সেখানে VARCHAR(100) বা DATE চলবে না; TEXT লিখুন। আসল প্রজেক্টে নতুন SQLite টেবিলের জন্য STRICT একটা যুক্তিসংগত ডিফল্ট।
টাইপ পৌঁছায় pandas-এ
টেবিল pandas-এ পড়লে প্রতিটা SQL টাইপ একটা dtype হয়ে যায়, আর NULL ও SQLite-এর টেক্সট তারিখ ফলাফলকে প্রভাবিত করে:
import pandas as pd
from sqlhelp import con
products = pd.read_sql("SELECT product_id, name, price, stock FROM products ORDER BY product_id", con)
print(products.dtypes)
orders = pd.read_sql("SELECT order_id, order_date FROM orders ORDER BY order_id", con,
parse_dates=["order_date"])
print(orders.dtypes)product_id int64
name str
price int64
stock float64
dtype: object
order_id int64
order_date datetime64[us]
dtype: objectতিনটা জিনিস খেয়াল করুন। stock হয়েছে float64, int64 নয়, কারণ এতে NULL আছে, আর pandas অনুপস্থিত সংখ্যা রাখে NaN হিসেবে, যা একটা float। টেক্সট কলাম দেখায় str (pandas 3.0; পুরোনো ভার্সন দেখায় object)। আর order_date আসল datetime হয়েছে শুধু parse_dates-এর কারণে; এটা ছাড়া SQLite যেভাবে রেখেছিল, সেভাবেই সাধারণ টেক্সট হিসেবে আসত।
ঠিক টাইপ বাছাই
| ডেটা | ভালো পছন্দ | কেন |
|---|---|---|
| id, কি | INTEGER; বড় বা দ্রুত বাড়া টেবিলে BIGINT | ছোট, তুলনা আর জয়েনে দ্রুত |
| গণনা, পরিমাণ, টোকেন | INTEGER / BIGINT | নিখুঁত; যোগফল অনেক বড় হতে পারে |
| টাকা | পয়সা/সেন্টে INTEGER, বা DECIMAL(12, 2) | নিখুঁত যোগফল; কখনো FLOAT নয় |
| স্কোর, সম্ভাবনা, পরিমাপ | REAL / DOUBLE PRECISION | আনুমানিক হলেও চলে; দ্রুত হিসাব |
| নাম, ইমেইল, স্ট্যাটাস | VARCHAR(n) (স্ট্যাটাসে + একটা CHECK) | সীমা উল্টোপাল্টা মান আটকায় |
| লম্বা টেক্সট: প্রম্পট, উত্তর, ডকুমেন্ট | TEXT | কোনো খামখেয়ালি সীমা নেই |
| নির্দিষ্ট দৈর্ঘ্যের কোড | CHAR(2), CHAR(3) | দৈর্ঘ্য সবসময় এক |
| ক্যালেন্ডারের তারিখ | DATE (SQLite-এ ISO TEXT) | ঠিকঠাক সাজে আর তুলনা হয় |
| ইভেন্টের সময়, লগ | TIMESTAMPTZ / UTC-তে DATETIME / UTC-তে ISO TEXT | একটাই দ্ব্যর্থহীন মুহূর্ত |
| হ্যাঁ/না ফ্ল্যাগ | BOOLEAN (SQLite-এ 0/1) | উদ্দেশ্য স্পষ্ট |
| এমবেডিং | pgvector-এর vector(n), বা BLOB | ভেক্টর সার্চের জন্য লাগে (অ্যাডভান্সড টিউটোরিয়াল) |
সাধারণ ভুল
- টাকার জন্য FLOAT বা REAL। যোগফলে একটু একটু করে ভগ্নাংশের গরমিল জমে।
INTEGERপয়সা বাDECIMAL(12, 2)রাখুন। - স্থানীয় রূপে টেক্সট হিসেবে তারিখ।
'08/03/2026'তারিখের মতো সাজে না, তুলনাও হয় না; আর এটা ৮ মার্চ, নাকি ৩ আগস্ট? ISO 8601 ব্যবহার করুন:'2026-03-08'। - টেক্সট হিসেবে রাখা সংখ্যা। সাজালে
'10'আসে'9'-এর আগে, আর যোগ করতে সব জায়গায় CAST লাগে। সংখ্যাকে সংখ্যার টাইপ দিন। - টাইম জোন ছাড়া টাইমস্ট্যাম্প। আলাদা জোনের দুটো সার্ভার একই মুহূর্তের জন্য আলাদা ঘড়ির সময় লেখে।
TIMESTAMPTZব্যবহার করুন, বা সবসময় UTC-তেই রাখুন। - টাইপ বা দৈর্ঘ্য খাটানোর জন্য SQLite-এর ওপর ভরসা। ডিফল্টে সে কোনোটাই করে না।
STRICTটেবিল ব্যবহার করুন, গুরুত্বপূর্ণ দৈর্ঘ্যের জন্য CHECK কনস্ট্রেইন্ট দিন, বা ইনসার্টের আগে Python-এ যাচাই করুন।
নিজে চেষ্টা করুন
- সহজ:
typeof()দিয়ে কাস্টমার ৫-এরname,cityআরjoined_on, এবং প্রোডাক্ট ৬-এরname,priceআরstock-এর স্টোরেজ ক্লাস বের করুন। কোন মানগুলো NULL? - মাঝারি: একটা STRICT SQLite টেবিল
llm_callsবানান, যাতে থাকবে পূর্ণসংখ্যার একটা id, মডেলের নাম, প্রম্পট আর কমপ্লিশনের টোকেন সংখ্যা, মাইক্রো-ডলারে খরচ (পূর্ণসংখ্যা), আর টেক্সট হিসেবে একটা UTC টাইমস্ট্যাম্প। একটা বৈধ সারি ইনসার্ট করুন, তারপর দেখান যে'many'টোকেন সংখ্যা ফিরিয়ে দেওয়া হয়। - কঠিন: কোর্স ইনস্ট্রাক্টরদের পেমেন্টের জন্য একটা PostgreSQL
CREATE TABLE payoutsলিখুন: id, ইনস্ট্রাক্টরের নাম, পয়সাসহ টাকার পরিমাণ, পেমেন্ট হয়েছে কিনা, আর ঠিক কোন মুহূর্তে হয়েছে। ঢাকার সময় বিকেল ৩টায় পরিশোধিত ১২৫০.৫০ টাকার একটা সারি ইনসার্ট করুন, আর আবার সিলেক্ট করে দেখুন।
উত্তর
-- 1: NULL-এর নিজস্ব স্টোরেজ ক্লাস আছে, 'null'
SELECT typeof(name), typeof(city), typeof(joined_on) FROM customers WHERE customer_id = 5;
SELECT typeof(name), typeof(price), typeof(stock) FROM products WHERE product_id = 6;
-- 2
CREATE TABLE llm_calls (
call_id INTEGER PRIMARY KEY,
model TEXT NOT NULL,
prompt_tokens INTEGER NOT NULL,
completion_tokens INTEGER NOT NULL,
cost_micro_usd INTEGER NOT NULL, -- 0.0042 USD রাখা হয় 4200 হিসেবে
called_at TEXT NOT NULL -- UTC-তে ISO 8601
) STRICT;
INSERT INTO llm_calls VALUES (1, 'small-model', 812, 145, 4200, '2026-03-08T04:00:00Z');
SELECT * FROM llm_calls;import sqlite3
from sqlhelp import con
# 2-এর বাকি অংশ: ভুল সারিটা ফিরিয়ে দেওয়া হয়
try:
con.execute("INSERT INTO llm_calls VALUES (2, 'small-model', 'many', 10, 100, '2026-03-08T04:01:00Z')")
except sqlite3.IntegrityError as error:
print(error)cannot store TEXT value in INTEGER column llm_calls.prompt_tokens-- PostgreSQL
-- 3
CREATE TABLE payouts (
payout_id BIGINT PRIMARY KEY,
instructor VARCHAR(100) NOT NULL,
amount NUMERIC(12, 2) NOT NULL CHECK (amount > 0),
is_paid BOOLEAN NOT NULL DEFAULT false,
paid_at TIMESTAMPTZ
);
INSERT INTO payouts VALUES (1, 'Lamia Karim', 1250.50, true, '2026-03-08 15:00:00+06');
SELECT * FROM payouts;পরিমাণটা ফেরত আসে নিখুঁত দশমিক হিসেবে, is_paid সত্যিকারের বুলিয়ান হিসেবে, আর paid_at আসে UTC-র সকাল ৯টার মুহূর্ত হিসেবে: UTC সেশনে দেখায় 09:00:00+00, আর Asia/Dhaka-তে সেট করা সেশনে 15:00:00+06।
সারসংক্ষেপ
- id, গণনা আর সবচেয়ে ছোট এককে টাকার জন্য পূর্ণসংখ্যা; নিখুঁত দশমিকের জন্য
DECIMAL/NUMERIC; ফ্লোট শুধু মাপা মানের জন্য। টাকার জন্য কখনো FLOAT নয়। - নির্দিষ্ট কোডের জন্য
CHAR(n), সীমাবদ্ধ টেক্সটের জন্যVARCHAR(n), লম্বা টেক্সটের জন্যTEXT। SQLite দৈর্ঘ্য উপেক্ষা করে; সার্ভারগুলো তা খাটায়, অক্ষর গুনে। - SQLite তারিখ রাখে ISO 8601 টেক্সট হিসেবে; MySQL আর PostgreSQL-এ আছে
DATEআর টাইমস্ট্যাম্প। মুহূর্ত রাখুন টাইম-জোন-সচেতন টাইপে, UTC-তে। - SQLite আর MySQL-এ বুলিয়ান হলো 0/1 (
TINYINT(1)), PostgreSQL-এ সত্যিকারেরBOOLEAN। NULL মানে ০-ও নয়,''-ও নয়। - SQLite-এর অ্যাফিনিটি পারলে বদলায়, না পারলে যা পায় তা-ই রাখে;
STRICTটেবিল তাকে টাইপ খাটাতে বাধ্য করে।
এরপর: CREATE, ALTER, DROP আর কনস্ট্রেইন্ট। প্রতিটা কলামের টাইপ বাছতে শিখেছেন, এবার পুরো টেবিল বানাবেন: কি, NOT NULL, UNIQUE, CHECK আর DEFAULT নিয়ম, আর ডেটা ভরা টেবিল কীভাবে বদলাতে হয়।