دیتابیس چیست؟
فرق فایل و دیتابیس، دیتابیس رابطهای (جدول، سطر، ستون) و انواع دیگر (key-value، سندی)، PostgreSQL و MySQL و SQLite؛ نصب PostgreSQL روی Ubuntu، ساختن کاربر و دیتابیس، psql و دستورهای بکاسلشی، اولین جدول با CREATE TABLE، و INSERT و SELECT ساده.
- حدود ۲۱ دقیقه مطالعه
- ۷ مثال اجراشده
- ۳ تمرین با جواب
- مقدماتی تا متوسط
- بهروزرسانی: ۲۹ مهر ۱۴۰۵
توی این درس یاد میگیری دیتابیس چیست و چرا تقریباً هر برنامهی واقعی به جای فایل از آن استفاده میکند. با مفهوم جدول (سطر و ستون) در دیتابیس رابطهای آشنا میشوی و میفهمی انواع دیگر (key-value مثل Redis، سندی مثل MongoDB) برای چهاند. بعد PostgreSQL را روی Ubuntu نصب میکنی، با ابزار خط فرمانش psql کار میکنی، اولین جدولت را با CREATE TABLE میسازی، چند سطر با INSERT اضافه میکنی و با SELECT میخوانی. و میبینی دیتابیس چطور جلوی دادهی غلط را خودش میگیرد.
مسئله: وقتی فایل دیگر کافی نیست
Section titled “مسئله: وقتی فایل دیگر کافی نیست”در دورهی پایتون داده را در یک فایل JSON یا CSV نگه داشتی. برای یک برنامهی کوچک عالی است. ولی فرض کن یک فروشگاه اینترنتی داری: ده هزار محصول، صد هزار سفارش، و همزمان پنجاه نفر در حال خرید. حالا این سؤالها پیش میآید:
- دو نفر همزمان آخرین عدد یک کالا را بخرند؛ چه کسی برنده است؟ (اگر هر دو فایل را بخوانند، کم کنند و بنویسند، یکی از خریدها گم میشود.)
- «سفارشهای هفتهی گذشتهی مشتریهای تهران که بالای یک میلیون تومان بودهاند» را چطور پیدا کنی، بدون اینکه کل فایل را هر بار بخوانی؟
- چه چیزی جلوی کسی را میگیرد که قیمت را «گران» بنویسد یا سفارشی برای مشتریای ثبت کند که وجود ندارد؟
دیتابیس (پایگاه داده) برنامهای است که دقیقاً برای همین سؤالها ساخته شده.
تشبیه: کتابخانه با کتابدار
Section titled “تشبیه: کتابخانه با کتابدار”فایل مثل یک جعبه کاغذ است: هر کس هر چه بخواهد داخلش میگذارد و برای پیدا کردن چیزی باید همه را ورق بزنی. دیتابیس مثل کتابخانه با کتابدار است: کتابها در قفسههای منظماند (جدولها)، هر کتاب شناسهی یکتا دارد، یک فهرست (ایندکس) سریع پیدایشان میکند، و کتابدار (موتور دیتابیس) نمیگذارد کسی کتاب بدون عنوان ثبت کند یا دو نفر همزمان یک کتاب را امانت بگیرند. تو با کتابدار به زبان مشخصی حرف میزنی: SQL.
جدول، سطر و ستون
Section titled “جدول، سطر و ستون”دیتابیس رابطهای (relational) داده را در جدولها نگه میدارد، خیلی شبیه یک برگهی اکسل ولی با قانون:
| id | name | price | stock |
|---|---|---|---|
| 1 | کتاب پایتون | 320000 | 12 |
| 2 | ماوس | 450000 | 30 |
| 3 | کیبورد | 890000 | 8 |
- ستون (column): یک ویژگی با نوع مشخص:
nameهمیشه متن،priceهمیشه عدد صحیح. - سطر (row): یک رکورد، اینجا یک محصول.
- کلید اصلی (primary key): ستونی که هر سطر را یکتا مشخص میکند (
id). دو محصول ممکن است هماسم باشند، ولی هرگز همشناسه نیستند.
«رابطهای» یعنی جدولها با هم رابطه دارند: جدول orders با یک ستون product_id به جدول products اشاره میکند (درس JOIN).
سه دیتابیس رابطهای معروف
Section titled “سه دیتابیس رابطهای معروف”| PostgreSQL | MySQL / MariaDB | SQLite | |
|---|---|---|---|
| نوع | سرور (سرویس جدا) | سرور | یک فایل، داخل خود برنامه |
| قوت | امکانات زیاد، دقیق، استاندارد، JSON و جستجوی متنی | بسیار رایج در وب (WordPress و…) | بدون نصب، صفر تنظیمات |
| کاربرد | بیشتر پروژههای جدید | میزبانیهای اشتراکی، سیستمهای قدیمیتر | اپ موبایل، ابزارهای کوچک، تست |
این دوره روی PostgreSQL است. SQL پایه در هر سه تقریباً یکی است، پس هر چه یاد بگیری بیشترش همهجا کار میکند.
مثالهای عملی
Section titled “مثالهای عملی”مثال ۱: نصب PostgreSQL
Section titled “مثال ۱: نصب PostgreSQL”روی ماشین تمرینی Ubuntu:
sudo apt updatesudo apt install postgresqlنصب، سرویس را خودش روشن و enable میکند (درس systemd):
systemctl status postgresql --no-pagerpsql --version● postgresql.service - PostgreSQL RDBMS Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; preset: enabled) Active: active (exited) since Wed 2026-10-21 09:12:40 UTC; 2min agopsql (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)PostgreSQL 16 همراه Ubuntu 24.04 است. (active (exited) برای این واحد عادی است؛ سرور واقعی در واحد postgresql@16-main اجرا میشود.) سرور روی پورت ۵۴۳۲ گوش میدهد؛ با sudo ss -tlnp | grep 5432 ببین (درس پورتها).
مثال ۲: کاربر و دیتابیس خودت
Section titled “مثال ۲: کاربر و دیتابیس خودت”نصب یک کاربر لینوکسی و یک نقش (role) دیتابیسی به اسم postgres میسازد که مدیر دیتابیس است. روی Ubuntu، کاربر لینوکسی ali بهطور پیشفرض بدون رمز به نقش دیتابیسی همنامش وصل میشود (به این peer authentication میگویند؛ درس کاربر و امنیت). پس یک نقش همنام خودت بساز و یک دیتابیس:
sudo -u postgres createuser --createdb $USERcreatedb shoppsql shoppsql (16.15 (Ubuntu 16.15-0ubuntu0.24.04.1))Type "help" for help.
shop=>sudo -u postgres createuser ...دستور را با کاربر لینوکسیpostgres(همان مدیر) اجرا میکند و نقشی با اسم تو ($USER، یعنیali) میسازد که اجازهی ساختن دیتابیس دارد.createdb shopیک دیتابیس به اسمshopمیسازد (حالا دیگر با نقش خودت).psql shopبه آن وصل میشود. پرامپتshop=>یعنی «در دیتابیس shop هستی و منتظر SQL ام». (برای مدیر،=#است؛ مثل$و#در ترمینال.)
یک سرور PostgreSQL میتواند چند دیتابیس جدا داشته باشد (مثلاً یکی برای هر برنامه)؛ هر دیتابیس هم جدولهای خودش را.
مثال ۳: دستورهای بکاسلشی psql
Section titled “مثال ۳: دستورهای بکاسلشی psql”دستورهایی که با \ شروع میشوند مال خود psqlاند، نه SQL، و نقطهویرگول لازم ندارند:
\l List of databases Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges-----------+----------+----------+-----------------+---------+---------+------------+-----------+----------------------- postgres | postgres | UTF8 | libc | C.UTF-8 | C.UTF-8 | | | shop | ali | UTF8 | libc | C.UTF-8 | C.UTF-8 | | | template0 | postgres | UTF8 | libc | C.UTF-8 | C.UTF-8 | | | =c/postgres +...(4 rows)| دستور | کار |
|---|---|
\l |
فهرست دیتابیسها |
\c نام |
وصل شدن به یک دیتابیس دیگر |
\dt |
فهرست جدولها |
\d جدول |
ساختار یک جدول |
\? / \h دستور |
راهنمای psql / راهنمای یک دستور SQL |
\x |
نمایش عمودی (برای سطرهای پهن) |
\q |
خروج (یا Ctrl+D) |
Encoding همه UTF8 است، پس فارسی بیدردسر ذخیره میشود.
مثال ۴: اولین جدول، CREATE TABLE
Section titled “مثال ۴: اولین جدول، CREATE TABLE”CREATE TABLE products ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL, stock INTEGER DEFAULT 0);CREATE TABLE- هر ستون: اسم و نوع.
TEXTمتن با هر طولی،INTEGERعدد صحیح. SERIAL PRIMARY KEY:idخودکار ۱، ۲، ۳… میشود و کلید اصلی است.NOT NULL: این ستون نمیتواند خالی باشد. (NULLدر SQL یعنی «مقدار نامعلوم/خالی».)DEFAULT 0: اگر مقدار ندادی، صفر.- دستور SQL با
;تمام میشود. کلمههای SQL را رسم است با حروف بزرگ بنویسی (CREATE) تا از اسمها جدا شوند؛ PostgreSQL به بزرگی و کوچکی آنها حساس نیست.
ساختار جدول را ببین:
\dt\d products List of relations Schema | Name | Type | Owner--------+----------+-------+------- public | products | table | ali(1 row)
Table "public.products" Column | Type | Collation | Nullable | Default--------+---------+-----------+----------+-------------------------------------- id | integer | | not null | nextval('products_id_seq'::regclass) name | text | | not null | price | integer | | not null | stock | integer | | | 0Indexes: "products_pkey" PRIMARY KEY, btree (id)SERIAL در واقع یک integer است که پیشفرضش از یک شمارنده (sequence) به اسم products_id_seq میآید. کلید اصلی هم خودکار یک ایندکس گرفت (درس ایندکس).
مثال ۵: افزودن و خواندن
Section titled “مثال ۵: افزودن و خواندن”INSERT INTO products (name, price, stock) VALUES ('کتاب پایتون', 320000, 12);INSERT INTO products (name, price, stock) VALUES ('ماوس', 450000, 30), ('کیبورد', 890000, 8);SELECT * FROM products;INSERT 0 1INSERT 0 2 id | name | price | stock----+-------------+--------+------- 1 | کتاب پایتون | 320000 | 12 2 | ماوس | 450000 | 30 3 | کیبورد | 890000 | 8(3 rows)INSERT INTO جدول (ستونها) VALUES (مقدارها)سطر اضافه میکند؛ با ویرگول بین پرانتزها، چند سطر یکجا.INSERT 0 2یعنی «دو سطر اضافه شد».- متن در SQL با کوتیشن تکی (
'...') است. (کوتیشن دوتایی معنی دیگری دارد؛ اشتباهات رایج.) idرا ندادیم؛ خودکار پر شد.SELECT * FROM productsهمهی ستونها (*) و همهی سطرها را برمیگرداند.
فقط ستونها و سطرهای مشخص:
SELECT name, price FROM products WHERE price < 500000; name | price-------------+-------- کتاب پایتون | 320000 ماوس | 450000(2 rows)WHERE فیلتر است؛ درس بعد مفصل.
دستور SQL در psql را با چه چیزی تمام میکنی؟
جواب درست: نقطهویرگول ;
بدون ; psql فکر میکند دستور ادامه دارد. دستورهای بکاسلشی مثل \dt نقطهویرگول نمیخواهند.
مثال ۶: دیتابیس از داده دفاع میکند
Section titled “مثال ۶: دیتابیس از داده دفاع میکند”INSERT INTO products (price) VALUES (1000);INSERT INTO products (name, price) VALUES ('هدفون', 'گران');ERROR: null value in column "name" of relation "products" violates not-null constraintDETAIL: Failing row contains (4, null, 1000, 0).ERROR: invalid input syntax for type integer: "گران"LINE 1: INSERT INTO products (name, price) VALUES ('هدفون', 'گران'); ^دو سطر غلط رد شدند: اولی اسم نداشت (NOT NULL) و دومی برای ستون عددی متن داد. فایل JSON هیچکدام را نمیگرفت. این قانونها (قید یا constraint) تضمین میکنند هر برنامهای که به این دیتابیس وصل شود، با هر زبانی، نتواند دادهی خراب بنویسد. (دقت کن 4 در DETAIL: شمارندهی id برای سطر ردشده هم جلو رفت؛ پس شمارهها ممکن است فاصله داشته باشند، و این عادی است.)
مثال ۷: دستور چندخطی و نقطهویرگول فراموششده
Section titled “مثال ۷: دستور چندخطی و نقطهویرگول فراموششده”اگر ; را فراموش کنی، psql منتظر ادامه میماند و پرامپت عوض میشود:
shop=> SELECT * FROM productsshop-> ; id | name | price | stock----+-------------+--------+-------...shop-> یعنی «دستورت هنوز تمام نشده». کافی است ; بزنی و Enter. اگر دستور را اشتباه شروع کردهای و میخواهی رهایش کنی، Ctrl+C بزن. همین امکان را میدهد که دستورهای طولانی را در چند خط و خوانا بنویسی (مثل CREATE TABLE بالا).
پشت پرده: کلاینت و سرور
Section titled “پشت پرده: کلاینت و سرور”PostgreSQL یک سرور است (درس کلاینت و سرور در دورهی مبانی): یک سرویس systemd که همیشه روشن است، داده را در فایلهایی زیر /var/lib/postgresql/16/main نگه میدارد و روی پورت ۵۴۳۲ (و یک سوکت محلی) منتظر درخواست است. psql فقط یک کلاینت است؛ برنامهی پایتون تو، یک پنل مدیریت گرافیکی یا یک اپ موبایل (از راه API) هم همینطور. همه با یک سرور حرف میزنند و سرور است که تصمیم میگیرد چه کسی چه کاری اجازه دارد، کدام تغییر اول ثبت شود و چطور داده بعد از قطع برق سالم بماند.
برای همین هرگز فایلهای داخل /var/lib/postgresql را مستقیم کپی یا ویرایش نکن؛ بکاپ و بازیابی ابزارهای خودش را دارد (درس بکاپ).
جدولهای مرجع
Section titled “جدولهای مرجع”| نوع داده | برای | نمونه |
|---|---|---|
INTEGER / BIGINT |
عدد صحیح / عدد خیلی بزرگ | 320000 |
NUMERIC(10,2) |
عدد اعشاری دقیق (پول) | 19.99 |
TEXT / VARCHAR(n) |
متن / متن با حداکثر طول | 'ماوس' |
BOOLEAN |
درست/غلط | true |
DATE / TIMESTAMPTZ |
تاریخ / زمان با منطقهی زمانی | '2026-10-21' |
SERIAL |
عدد خودکار برای کلید اصلی |
| قید | معنی |
|---|---|
PRIMARY KEY |
یکتا و غیرخالی؛ شناسهی سطر |
NOT NULL |
خالی نباشد |
DEFAULT v |
مقدار پیشفرض |
UNIQUE |
تکراری نباشد |
CHECK (شرط) |
شرط دلخواه، مثلاً CHECK (price >= 0) |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) کوتیشن دوتایی برای متن
Section titled “۱) کوتیشن دوتایی برای متن”INSERT INTO products (name, price) VALUES ("ماوس", 1); خطای column "ماوس" does not exist میدهد؛ در SQL کوتیشن دوتایی برای اسم (جدول، ستون) است و تکی برای متن. راهحل: 'ماوس'.
۲) نوشتن SQL در ترمینال لینوکس
Section titled “۲) نوشتن SQL در ترمینال لینوکس”bash: SELECT: command not foundSQL را باید داخل psql نوشت. راهحل: اول psql shop، یا برای یک دستور: psql shop -c "SELECT * FROM products;".
۳) جدولی که نیست
Section titled “۳) جدولی که نیست”ERROR: relation "prodcts" does not existLINE 1: SELECT * FROM prodcts; ^PostgreSQL به جدول میگوید relation. یا غلط تایپی است، یا به دیتابیس دیگری وصلی. راهحل: \dt و دقت به پرامپت (shop=>).
۴) role "ali" does not exist
Section titled “۴) role "ali" does not exist”psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "ali" does not existنقش دیتابیسی همنام کاربر لینوکسیات ساخته نشده. راهحل: مثال ۲ (sudo -u postgres createuser --createdb $USER).
۵) دست زدن مستقیم به فایلهای داده
Section titled “۵) دست زدن مستقیم به فایلهای داده”کپی یا پاک کردن چیزی در /var/lib/postgresql وقتی سرور روشن است، دیتابیس را خراب میکند. راهحل: فقط با SQL و ابزارهای PostgreSQL (pg_dump در درس بکاپ).
دیتابیس جدیدی به اسم practice بساز، به آن وصل شو، با \l ببین ساخته شده و با \c shop به دیتابیس shop برگرد.
دیدن جواب
createdb practicepsql practice\l\c shopYou are now connected to database "shop" as user "ali".shop=>در فهرست \l سطر practice با Owner ali دیده میشود.
تمرین اصلی: در shop جدول customers بساز با ستونهای id (خودکار، کلید اصلی)، name (متن، اجباری)، city (متن) و phone (متن، یکتا). سه مشتری اضافه کن و همه را بخوان. بعد ثابت کن دیتابیس اجازهی شمارهی تکراری نمیدهد.
دیدن جواب
CREATE TABLE customers ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, city TEXT, phone TEXT UNIQUE);INSERT INTO customers (name, city, phone) VALUES ('علی رضایی', 'تهران', '09120000001'), ('سارا محمدی', 'اصفهان', '09130000002'), ('رضا کریمی', 'تهران', '09120000003');SELECT * FROM customers;INSERT INTO customers (name, phone) VALUES ('مینا', '09120000001');CREATE TABLEINSERT 0 3 id | name | city | phone----+------------+--------+------------- 1 | علی رضایی | تهران | 09120000001 2 | سارا محمدی | اصفهان | 09130000002 3 | رضا کریمی | تهران | 09120000003(3 rows)
ERROR: duplicate key value violates unique constraint "customers_phone_key"DETAIL: Key (phone)=(09120000001) already exists.شماره تلفن را TEXT گرفتیم نه عدد، چون صفر اولش مهم است و کسی رویش حساب انجام نمیدهد.
به جدول products قیدی اضافه کن که قیمت منفی ممنوع باشد، و ثابت کن کار میکند. (راهنما: ALTER TABLE products ADD CONSTRAINT price_positive CHECK (price >= 0);) بعد با \d products ببین قید کجا نمایش داده میشود.
دیدن جواب
ALTER TABLE products ADD CONSTRAINT price_positive CHECK (price >= 0);INSERT INTO products (name, price) VALUES ('تخفیف عجیب', -5000);ALTER TABLEERROR: new row for relation "products" violates check constraint "price_positive"DETAIL: Failing row contains (5, تخفیف عجیب, -5000, 0).Indexes: "products_pkey" PRIMARY KEY, btree (id)Check constraints: "price_positive" CHECK (price >= 0)ALTER TABLE ساختار یک جدول موجود را عوض میکند. PostgreSQL قبل از افزودن قید، سطرهای فعلی را هم بررسی میکند؛ اگر از قبل قیمت منفی وجود داشت، قید اضافه نمیشد.
آزمونک
Section titled “آزمونک”مهمترین فرق دیتابیس با فایل JSON برای یک فروشگاه چندکاربره؟
جواب درست: دیتابیس همزمانی، قانونهای داده و جستجوی سریع را مدیریت میکند
تراکنش، قید و ایندکس.
در جدول، کلید اصلی (PRIMARY KEY) چیست؟
جواب درست: ستونی که هر سطر را یکتا مشخص میکند
یکتا و غیرخالی.
پرامپت shop-> در psql یعنی…
جواب درست: دستورت تمام نشده (احتمالاً ; جا افتاده)
با ; تمامش کن.
متن در SQL با کدام کوتیشن؟
جواب درست: تکی '
دوتایی برای اسم جدول و ستون است.
\dt در psql چه میکند؟
جواب درست: فهرست جدولها
\d نام ساختار یک جدول را میدهد.
INSERT با name خالی در ستون NOT NULL چه میشود؟
جواب درست: رد میشود با خطای not-null constraint
قیدها از داده دفاع میکنند.
جمعبندی
Section titled “جمعبندی”- دیتابیس برنامهای است برای نگه داشتن داده با همزمانی امن، قانونهای داده و جستجوی سریع؛ زبانش SQL.
- رابطهای: جدول (سطر و ستون نوعدار)، کلید اصلی، رابطه بین جدولها. NoSQL برای کارهای خاص.
- نصب:
sudo apt install postgresql؛ نقش و دیتابیس:sudo -u postgres createuser --createdb $USERوcreatedb shop؛ اتصال:psql shop. - psql:
\l،\c،\dt،\d،\q؛ SQL با;تمام میشود. CREATE TABLEبا نوع و قید (PRIMARY KEY،NOT NULL،DEFAULT،UNIQUE،CHECK)؛INSERT INTO ... VALUES ...؛SELECT ... FROM ... WHERE ....- متن با کوتیشن تکی؛ دیتابیس دادهی غلط را خودش رد میکند.
| دستور | کاری که میکند |
|---|---|
sudo apt install postgresql | نصب |
sudo -u postgres createuser --createdb $USER | نقش همنام خودت |
createdb shop / psql shop | ساختن و وصل شدن |
\l \c db \dt \d t \q | دستورهای psql |
CREATE TABLE t (id SERIAL PRIMARY KEY, ...); | ساختن جدول |
INSERT INTO t (a, b) VALUES ('x', 1); | افزودن سطر |
SELECT * FROM t WHERE ...; | خواندن |
psql shop -c "SELECT 1;" | اجرای یک دستور از ترمینال |