Kodax

CRUD Operations — SQL الأساسيات

عمليات CRUD

كل الأمثلة تفترض الجداول التالية (المثال الكامل ينشئها):

CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT NOT NULL UNIQUE,
  city TEXT,
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  total REAL NOT NULL CHECK (total >= 0),
  status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'paid', 'cancelled')),
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

INSERT INTO users (id, name, email, city) VALUES
  (1, 'سارة', 'sara@example.com', 'بغداد'),
  (2, 'عمر', 'omar@example.com', 'البصرة'),
  (3, 'ليلى', 'layla@example.com', 'بغداد'),
  (4, 'زيد', 'zaid@example.com', NULL);

INSERT INTO orders (user_id, total, status) VALUES
  (1, 120.0, 'paid'), (1, 45.5, 'paid'), (2, 300.0, 'pending'),
  (3, 80.0, 'paid'), (3, 15.0, 'cancelled'), (1, 60.0, 'pending');

INSERT — إضافة

CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price REAL NOT NULL);
INSERT INTO products (name, price) VALUES ('قلم', 1.5);
INSERT INTO products (name, price) VALUES ('دفتر', 3.0), ('ممحاة', 0.5);   -- عدة صفوف

اكتب أسماء الأعمدة دائماً: يحمي كودك إذا أُضيف عمود جديد للجدول لاحقاً.

SELECT — قراءة

CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price REAL NOT NULL, category TEXT);
INSERT INTO products (name, price, category) VALUES ('قلم', 1.5, 'قرطاسية'), ('سماعة', 25, 'إلكترونيات'), ('دفتر', 3, 'قرطاسية');

SELECT name, price FROM products WHERE category = 'قرطاسية' AND price < 5 ORDER BY price DESC LIMIT 10;
SELECT * FROM products WHERE name LIKE '%ف%';          -- يحتوي "ف"
SELECT * FROM products WHERE price BETWEEN 2 AND 30;
SELECT * FROM products WHERE category IN ('قرطاسية', 'كتب');
SELECT DISTINCT category FROM products;

- اطلب الأعمدة التي تحتاجها بدل * في كود الإنتاج.

- ORDER BY ضروري إن كان الترتيب يهمك؛ بدونه الترتيب غير مضمون.

NULL: ليس قيمة بل "غير معروف"

CREATE TABLE people (name TEXT, city TEXT);
INSERT INTO people VALUES ('سارة', 'بغداد'), ('زيد', NULL);
SELECT * FROM people WHERE city = NULL;        -- لا يعيد شيئاً أبداً!
SELECT * FROM people WHERE city IS NULL;       -- الصحيح
SELECT name, COALESCE(city, 'غير محدد') AS city FROM people;

أي مقارنة مع NULL نتيجتها "غير معروف" (لا صحيح ولا خطأ). و city <> 'بغداد' لا تعيد صفوف NULL أيضاً.

UPDATE — تعديل

CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price REAL);
INSERT INTO products VALUES (1, 'قلم', 1.5), (2, 'دفتر', 3);
UPDATE products SET price = price * 1.10 WHERE id = 2;

DELETE — حذف

CREATE TABLE sessions (id INTEGER PRIMARY KEY, expires_at TEXT);
INSERT INTO sessions VALUES (1, '2020-01-01'), (2, '2999-01-01');
DELETE FROM sessions WHERE expires_at < date('now');

⚠️ الخطأ الأخطر

UPDATE products SET price = 0; أو DELETE FROM users; بلا WHERE يعدّل/يحذف كل الصفوف. عادات تحميك:

1. اكتب الاستعلام كـ SELECT ... WHERE ... أولاً وتأكد من الصفوف، ثم حوّله.

2. نفّذ داخل معاملة (BEGIN ... ثم ROLLBACK إن أخطأت) — درس المعاملات.

3. نسخ احتياطية دائماً، وصلاحيات محدودة لمستخدم التطبيق.

الحذف الناعم

تطبيقات كثيرة لا تحذف فعلاً بل تضع deleted_at وتستبعد هذه الصفوف في الاستعلامات — للاستعادة والتدقيق.

تمرين

على جداول المثال: أضف مستخدماً، اعرض الطلبات المدفوعة بترتيب تنازلي للمبلغ، غيّر حالة الطلبات المعلقة الأقدم من 30 يوماً إلى cancelled (جرّبها كـ SELECT أولاً)، واعرض المستخدمين بلا مدينة.

CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT NOT NULL UNIQUE,
  city TEXT,
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  total REAL NOT NULL CHECK (total >= 0),
  status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'paid', 'cancelled')),
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

INSERT INTO users (id, name, email, city) VALUES
  (1, 'سارة', 'sara@example.com', 'بغداد'),
  (2, 'عمر', 'omar@example.com', 'البصرة'),
  (3, 'ليلى', 'layla@example.com', 'بغداد'),
  (4, 'زيد', 'zaid@example.com', NULL);

INSERT INTO orders (user_id, total, status) VALUES
  (1, 120.0, 'paid'), (1, 45.5, 'paid'), (2, 300.0, 'pending'),
  (3, 80.0, 'paid'), (3, 15.0, 'cancelled'), (1, 60.0, 'pending');

-- قراءة
SELECT id, name, city FROM users WHERE city = 'بغداد' ORDER BY name;
SELECT name, COALESCE(city, 'غير محدد') AS city FROM users WHERE city IS NULL;

-- تعديل: جرّب الشرط بـ SELECT أولاً
SELECT id, status FROM orders WHERE status = 'pending' AND user_id = 1;
UPDATE orders SET status = 'paid' WHERE status = 'pending' AND user_id = 1;

-- حذف بشرط
DELETE FROM orders WHERE status = 'cancelled';

SELECT status, COUNT(*) AS n FROM orders GROUP BY status;
اختبر فهمك