الدوال المتقدمة
الدوال المتقدمة
🌍 تشبيه من العالم האמיתי
SQL تشبه السويس.army knife — بالإضافة إلى "السكين" (الاستعلامات) و"المنشار" (التجميع) اللذين تعلمتهم بالفعل، لديها العديد من الأدوات المفيدة الأخرى:
- دوال النصوص = محرر نصوص — الربط، والاستخراج، وتحويل حالة الأحرف
- دوال الأرقام = آلة حاسبة — التقريب، والتقريب للأسفل، والقيم المطلقة
- دوال التواريخ = تقويم — الحصول على التاريخ الحالي، حساب الفرق بين الأيام، واستخراج السنة/الشهر/اليوم
- تحويل الأنواع = مترجم — التحويل بين الأرقام والنصوص والتواريخ
إتقان هذه الدوال يتيح لك إجراء المزيد من معالجة البيانات في SQL، مما يقلل الحاجة إلى معالجة إضافية في طبقة التطبيق.
🎯 المفاهيم الأساسية
دوال النصوص
CONCAT — ربط النصوص
يجمع عدة نصوص في نص واحد.
-- ربط الاسم
SELECT CONCAT(first_name, ' ', last_name) AS full_name
FROM employees;
-- MySQL يدعم أيضًا || للربط (يتطلب تفعيل PIPES_AS_CONCAT)
-- SELECT first_name || ' ' || last_name FROM employees;
SUBSTRING — استخراج جزء من النص
يستخرج جزءًا من النص.
-- استخراج جزء اسم المستخدم من البريد الإلكتروني (قبل @)
SELECT email, SUBSTRING(email, 1, POSITION('@' IN email) - 1) AS username
FROM employees
WHERE email IS NOT NULL;
-- استخراج بسيط: ابدأ من الموضع 1، خذ 3 أحرف
SELECT SUBSTRING('Hello World', 1, 3); -- النتيجة: Hel
UPPER / LOWER — تحويل حالة الأحرف
SELECT UPPER('hello') AS uppercase, LOWER('WORLD') AS lowercase;
-- النتيجة: HELLO, world
-- استخدام عملي: بحث غير حساس لحالة الأحرف
SELECT * FROM employees WHERE LOWER(email) = 'zhangsan@company.com';
TRIM — إزالة المسافات
-- إزالة المسافات من البداية والنهاية
SELECT TRIM(' hello ') AS trimmed; -- النتيجة: hello
-- إزالة أحرف محددة
SELECT TRIM(LEADING '0' FROM '0012300'); -- النتيجة: 12300
REPLACE — استبدال النصوص
-- إخفاء الأرقام الأربعة الوسطى من رقم الهاتف بـ ****
SELECT phone, REPLACE(phone, SUBSTRING(phone, 4, 4), '****') AS masked
FROM employees;
LENGTH — طول النص
SELECT first_name, LENGTH(first_name) AS name_len
FROM employees;
دوال الأرقام
ROUND — التقريب
SELECT ROUND(3.14159, 2); -- النتيجة: 3.14
SELECT ROUND(3.14159, 0); -- النتيجة: 3
SELECT ROUND(1234.5, -2); -- النتيجة: 1200 (تقريب للمئات)
CEIL / FLOOR — التقريب للأعلى / للأسفل
SELECT CEIL(3.1); -- النتيجة: 4 (تقريب للأعلى)
SELECT CEIL(3.0); -- النتيجة: 3
SELECT FLOOR(3.9); -- النتيجة: 3 (تقريب للأسفل)
SELECT FLOOR(3.0); -- النتيجة: 3
CEILING()، وOracle يستخدم CEIL().
ABS — القيمة المطلقة
SELECT ABS(-100); -- النتيجة: 100
SELECT ABS(50); -- النتيجة: 50
MOD — باقي القسمة
SELECT MOD(10, 3); -- النتيجة: 1
SELECT MOD(100, 7); -- النتيجة: 2
-- SQL Server لا يدعم دالة MOD، استخدم % بدلاً من ذلك
-- SELECT 10 % 3; -- النتيجة: 1
دوال التواريخ
NOW — التاريخ والوقت الحالي
SELECT NOW(); -- النتيجة: 2026-06-28 14:30:00 (الوقت الحالي)
SELECT CURDATE(); -- النتيجة: 2026-06-28 (التاريخ فقط)
SELECT CURTIME(); -- النتيجة: 14:30:00 (الوقت فقط)
GETDATE() بدلاً من NOW().
DATE — استخراج جزء التاريخ
SELECT DATE(NOW()); -- النتيجة: 2026-06-28
-- استخراج السنة والشهر واليوم
SELECT EXTRACT(YEAR FROM order_date) AS year,
EXTRACT(MONTH FROM order_date) AS month,
EXTRACT(DAY FROM order_date) AS day
FROM orders;
DATEDIFF — الفرق بين التواريخ
-- حساب عدد الأيام بين تاريخين
SELECT DATEDIFF('2026-12-31', '2026-01-01'); -- النتيجة: 364
-- حساب مدة خدمة الموظف بالأيام
SELECT first_name, hire_date,
DATEDIFF(CURDATE(), hire_date) AS tenure_days
FROM employees;
DATEDIFF(date1, date2) في MySQL يحسب date1 - date2. يستخدم SQL Server نفس الترتيب. PostgreSQL يستخدم date1 - date2 للطرح المباشر.
DATE_FORMAT — تنسيق التاريخ
-- MySQL
SELECT DATE_FORMAT(order_date, '%Y-%m-%d') AS formatted_date
FROM orders;
-- SQL Server
-- SELECT FORMAT(order_date, 'yyyy-MM-dd') FROM orders;
EXTRACT — استخراج أجزاء التاريخ
SELECT EXTRACT(YEAR FROM order_date) AS year,
EXTRACT(MONTH FROM order_date) AS month,
EXTRACT(DAY FROM order_date) AS day,
EXTRACT(HOUR FROM NOW()) AS hour
FROM orders;
تحويل الأنواع
CAST — تحويل النوع (SQL قياسي)
-- نص إلى عدد صحيح
SELECT CAST('123' AS SIGNED INTEGER); -- MySQL
SELECT CAST('123' AS INT); -- SQL Server
-- عدد إلى نص
SELECT CAST(12345 AS CHAR);
-- تاريخ إلى نص
SELECT CAST(order_date AS CHAR) FROM orders;
-- نص إلى تاريخ
SELECT CAST('2026-06-28' AS DATE);
CONVERT — تحويل النوع (MySQL / SQL Server)
-- MySQL
SELECT CONVERT('123', SIGNED INTEGER);
SELECT CONVERT(123, CHAR);
-- SQL Server
SELECT CONVERT(INT, '123');
SELECT CONVERT(VARCHAR, 12345);
CAST هو المعيار في SQL وله توافق أفضل — يُوصى به. يختلف CONVERT اختلافًا كبيرًا في الصيغة عبر قواعد البيانات.
📝 الصيغة الأساسية
-- دوال النصوص
SELECT CONCAT(string1, string2) AS concatenated,
SUBSTRING(string, start_position, length) AS extracted,
UPPER(string) AS uppercase,
LOWER(string) AS lowercase,
TRIM(string) AS trimmed,
REPLACE(string, old_value, new_value) AS replaced,
LENGTH(string) AS length;
-- دوال الأرقام
SELECT ROUND(number, decimal_places) AS rounded,
CEIL(number) AS rounded_up,
FLOOR(number) AS rounded_down,
ABS(number) AS absolute,
MOD(number1, number2) AS remainder;
-- دوال التواريخ
SELECT NOW() AS current_time,
CURDATE() AS current_date,
DATEDIFF(date1, date2) AS day_difference,
EXTRACT(YEAR FROM date) AS year;
-- تحويل الأنواع
SELECT CAST(value AS target_type) AS converted;
- قد تختلف أسماء الدوال والمعاملات عبر قواعد البيانات — راجع التوثيق المقابل قبل الاستخدام
CASTهو المعيار في SQL ويُوصى به؛ يختلفCONVERTفي الصيغة بين MySQL و SQL Server- دوال التواريخ هي الأكثر اختلافًا — انتبه بشكل خاص عند التطوير عبر قواعد البيانات
📌 أمثلة
مثال: معالجة النصوص — تنسيق معلومات الموظفين
SELECT
CONCAT(UPPER(last_name), ', ', first_name) AS name,
LOWER(email) AS email,
SUBSTRING(phone, 1, 3) AS area_code,
LENGTH(first_name) AS first_name_length,
REPLACE(department_id, NULL, 'Unassigned') AS department
FROM employees
ORDER BY last_name;
الناتج:
name email area_code first_name_length department
----------- ---------------------- --------- ----------------- ----------
LI, Si lisi@company.com 138 2 2
WANG, Wu wangwu@company.com 139 2 2
ZHANG, San zhangsan@company.com 137 2 1
CONCAT + UPPER يقوم بتنسيق الاسم، LOWER يوحّد البريد الإلكتروني إلى أحرف صغيرة، SUBSTRING يستخرج أول 3 أرقام من رقم الهاتف.
مثال: الحسابات الرقمية — معالجة مبالغ الطلبات
SELECT
order_id,
total_amount AS original_amount,
ROUND(total_amount * 0.9, 2) AS discounted_amount,
CEIL(total_amount / 1000) AS thousands_ceil,
FLOOR(total_amount / 1000) AS thousands_floor,
MOD(total_amount, 100) AS remainder
FROM orders
WHERE status = 'completed';
الناتج:
order_id original_amount discounted_amount thousands_ceil thousands_floor remainder
-------- -------------- ----------------- -------------- --------------- ---------
1 15000.00 13500.00 15 15 0.00
2 8500.00 7650.00 9 8 0.00
3 3200.00 2880.00 4 3 0.00
ROUND يحسب السعر بعد خصم 10%، CEIL و FLOOR يقومان بالتريب للأعلى والأسفل إلى أقرب ألف على التوالي، MOD يحسب الباقي.
مثال: حساب التواريخ + تحويل الأنواع
SELECT
first_name AS name,
hire_date AS hire_date,
DATEDIFF(CURDATE(), hire_date) AS tenure_days,
EXTRACT(YEAR FROM hire_date) AS hire_year,
CONCAT(CAST(salary AS CHAR), ' yuan') AS salary_display,
DATE_FORMAT(hire_date, '%Y-%m') AS hire_month
FROM employees
ORDER BY hire_date;
الناتج:
name hire_date tenure_days hire_year salary_display hire_month
------ ---------- ----------- --------- -------------- ----------
Zhang 2023-03-15 1199 2023 15000.00 yuan 2023-03
Li 2023-07-01 1089 2023 18000.00 yuan 2023-07
Wang 2024-01-10 899 2024 12000.00 yuan 2024-01
DATEDIFF يحسب مدة الخدمة بالأيام، EXTRACT يستخرج السنة، CAST يتحويل الراتب إلى نص قبل ربط الوحدة، DATE_FORMAT يقوم بتنسيق التاريخ.
🎬 سيناريوهات تطبيقية
السيناريو 1: تنظيف البيانات — توحيد الصيغ
البيانات في قاعدة البيانات بصيغ غير متسقة وتحتاج إلى تنظيف للعرض.
SELECT
employee_id,
CONCAT(UPPER(TRIM(last_name)), ', ', TRIM(first_name)) AS standard_name,
LOWER(TRIM(email)) AS standard_email,
REPLACE(REPLACE(phone, '-', ''), ' ', '') AS standard_phone,
CAST(salary AS DECIMAL(10,2)) AS standard_salary
FROM employees
WHERE email IS NOT NULL;
TRIM يزيل المسافات الزائدة، UPPER/LOWER يوحّد حالة الأحرف، REPLACE ينظف الأحرف الخاصة من أرقام الهواتف، CAST يضمن اتساق أنواع البيانات.
السيناريو 2: الإحصائيات التقاريرية — تحليل على أساس الوقت
تحليل بيانات الطلبات حسب الربع.
SELECT
EXTRACT(YEAR FROM order_date) AS year,
CEIL(EXTRACT(MONTH FROM order_date) / 3.0) AS quarter,
COUNT(*) AS order_count,
ROUND(SUM(total_amount), 2) AS total_amount,
ROUND(AVG(total_amount), 2) AS avg_order_amount,
DATEDIFF(MAX(order_date), MIN(order_date)) AS span_days
FROM orders
WHERE status != 'cancelled'
GROUP BY EXTRACT(YEAR FROM order_date), CEIL(EXTRACT(MONTH FROM order_date) / 3.0)
ORDER BY year, quarter;
CEIL(MONTH / 3.0) يحول الأشهر إلى أرباع (1-3→Q1، 4-6→Q2، إلخ). DATEDIFF يحسب المدة الزمنية لكل ربع.
❓ أسئلة شائعة
س: ماذا يحدث عندما يواجه CONCAT قيمة NULL? ج: في MySQL، يُرجع
CONCATالقيمة NULL عندما يواجه NULL. لمعاملة NULL كنص فارغ، استخدمCOALESCE:CONCAT(COALESCE(first_name, ''), ' ', last_name). في PostgreSQL، يُرجع عامل||أيضًا NULL عند مواجهة NULL.
س: ما الفرق بين ROUND و CEIL/FLOOR? ج:
ROUNDيُقرب إلى عدد محدد من المنازل العشرية،CEILيُقرب لأقرب عدد صحيح للأعلى، وFLOORيُقرب لأقرب عدد صحيح للأسفل. على سبيل المثال، 3.5:ROUND(3.5)= 4،CEIL(3.1)= 4،FLOOR(3.9)= 3.
س: هل تختلف دوال التواريخ اختلافًا كبيرًا عبر قواعد البيانات? ج: نعم، الاختلافات كبيرة. يستخدم MySQL
NOW()وDATEDIFF()وDATE_FORMAT()؛ يستخدم SQL ServerGETDATE()وDATEDIFF()وFORMAT()؛ يستخدم PostgreSQLNOW()وطرح التواريخ وTO_CHAR(). راجع التوثيق المقابل عند التطوير عبر قواعد البيانات.
س: هل أستخدم CAST أم CONVERT? ج: استخدم
CAST— وهو المعيار في SQL وتدعمه جميع قواعد البيانات الرئيسية. يختلفCONVERTفي الصيغة بين MySQL و SQL Server، مما ينتج عنه توافق أسوأ.
📖 ملخص
| الفئة | الدوال الشائعة | الغرض |
|---|---|---|
| النصوص | CONCAT, SUBSTRING, UPPER, LOWER, TRIM, REPLACE, LENGTH | الربط، الاستخراج، التحويل، التنظيف |
| الأرقام | ROUND, CEIL, FLOOR, ABS, MOD | التقريب، التقريب للأسفل، باقي القسمة |
| التواريخ | NOW, CURDATE, DATEDIFF, EXTRACT, DATE_FORMAT | الحصول على الوقت، حساب الفروقات، استخراج الأجزاء |
| تحويل الأنواع | CAST, CONVERT | تحويل نوع البيانات |
- تُستخدم دوال النصوص لتنظيف البيانات وتنسيقها
- تُستخدم دوال الأرقام للحسابات الرياضية والتحكم في الدقة
- تُستخدم دوال التواريخ لحسابات الوقت وإحصائيات التقارير
CASTهو دالة تحويل النوع المعيارية في SQL ويُوصى بها- قد تختلف أسماء الدوال والصيغ عبر قواعد البيانات — انتبه عند التطوير عبر قواعد البيانات
📝 تمارين
التمرين 1 (⭐): استعلم من جدول employees، اربط first_name و last_name في اسم كامل (أحرف كبيرة)، واحسب مدة خدمة كل شخص بالأيام.
التمرين 2 (⭐⭐): استعلم من جدول orders، جمّع عدد الطلبات والمبلغ الإجمالي حسب الشهر، باستخدام EXTRACT لاستخراج السنة والشهر، و ROUND للحفاظ على منزلتين عشريتين.
التمرين 3 (⭐⭐⭐): استعلم من جدول employees لإنشاء "بطاقة عمل للموظف" بالصيغة: [القسم] الاسم (سنة التعيين) - الراتب الشهري: xxxxx وحدة. استخدم دوال النصوص للربط و CAST لتحويل الأرقام إلى نصوص.
الدرس التالي
👉 16-case-when - التعبيرات الشرطية: تعلّم التعبيرات الشرطية CASE WHEN وإتقان المنطق الشرطي في SQL!



