MySQL وتصميم قواعد البيانات

دوال السلسلة النصية والتاريخ المتقدمة

13 دقيقة الدرس 12 من 40

دوال السلسلة النصية والتاريخ المتقدمة

معالجة السلاسل النصية والتاريخ هي مهارات أساسية لمعالجة البيانات وتحويلها. يوفر MySQL دوال قوية لتنظيف وتنسيق وتحليل البيانات النصية والزمنية. إتقان هذه الدوال سيحسن بشكل كبير قدراتك على معالجة البيانات.

دوال السلسلة النصية المتقدمة

SUBSTRING_INDEX() - تقسيم السلاسل النصية

تستخرج SUBSTRING_INDEX() أجزاء من السلاسل النصية بناءً على المحددات:

-- استخراج النطاق من البريد الإلكتروني SELECT email, SUBSTRING_INDEX(email, '@', 1) AS username, SUBSTRING_INDEX(email, '@', -1) AS domain FROM customers; -- استخراج الاسم الأول من الاسم الكامل SELECT full_name, SUBSTRING_INDEX(full_name, ' ', 1) AS first_name, SUBSTRING_INDEX(full_name, ' ', -1) AS last_name FROM employees;
-- استخراج النطاق الفرعي من URL SELECT url, SUBSTRING_INDEX(SUBSTRING_INDEX(url, '://', -1), '.', 1) AS subdomain, SUBSTRING_INDEX(SUBSTRING_INDEX(url, '://', -1), '/', 1) AS domain FROM websites; -- مثال: https://shop.example.com/products -- subdomain: shop -- domain: shop.example.com

REPLACE() وتنظيف السلاسل النصية

-- تنظيف أرقام الهاتف SELECT phone, REPLACE(REPLACE(REPLACE(phone, '-', ''), ' ', ''), '(', '') AS cleaned_phone FROM contacts; -- توحيد أكواد المنتجات SELECT product_code, UPPER(REPLACE(TRIM(product_code), ' ', '-')) AS standardized_code FROM products;
-- استبدالات متعددة باستخدام REPLACE المتداخلة UPDATE products SET description = REPLACE( REPLACE( REPLACE(description, '&', 'and'), ' ', ' ' ), '\n\n', '\n' ) WHERE description IS NOT NULL;

REGEXP - التعبيرات النمطية

يدعم MySQL التعبيرات النمطية لمطابقة الأنماط والاستخراج:

-- البحث عن رسائل البريد الإلكتروني بنمط معين SELECT email FROM customers WHERE email REGEXP '^[a-z0-9]+@[a-z0-9]+\.[a-z]{2,}$'; -- البحث عن المنتجات بأكواد رقمية SELECT product_name, product_code FROM products WHERE product_code REGEXP '^[A-Z]{2}[0-9]{4}$'; -- يطابق: AB1234, XY9999 -- استخراج الأرقام من النص SELECT description, REGEXP_SUBSTR(description, '[0-9]+') AS first_number FROM products;
دوال MySQL 8.0+: توفر REGEXP_REPLACE() و REGEXP_SUBSTR() و REGEXP_INSTR() عمليات regex متقدمة للبحث والاستبدال والاستخراج وإيجاد الموضع.
-- REGEXP_REPLACE: إزالة الأحرف غير الأبجدية الرقمية SELECT product_name, REGEXP_REPLACE(product_name, '[^a-zA-Z0-9 ]', '') AS cleaned_name FROM products; -- REGEXP_SUBSTR: استخراج نمط معين SELECT text, REGEXP_SUBSTR(text, '\b[A-Z]{2}[0-9]{3}\b') AS code FROM documents;

معالجة السلسلة النصية المتقدمة

-- ملء السلاسل النصية إلى عرض ثابت SELECT product_code, LPAD(product_code, 10, '0') AS padded_code, RPAD(customer_name, 30, '.') AS formatted_name FROM orders; -- عكس السلسلة النصية SELECT REVERSE('MySQL') AS reversed; -- LQSyM -- توليد الأحرف الأولى SELECT full_name, CONCAT( UPPER(SUBSTRING(SUBSTRING_INDEX(full_name, ' ', 1), 1, 1)), UPPER(SUBSTRING(SUBSTRING_INDEX(full_name, ' ', -1), 1, 1)) ) AS initials FROM employees; -- John Smith → JS

دوال التاريخ والوقت المتقدمة

حسابات وعمليات التاريخ

-- حساب العمر من تاريخ الميلاد SELECT birth_date, TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age, TIMESTAMPDIFF(MONTH, birth_date, CURDATE()) AS age_in_months FROM customers; -- الأيام حتى/منذ الحدث SELECT event_name, event_date, DATEDIFF(event_date, CURDATE()) AS days_until_event, CASE WHEN DATEDIFF(event_date, CURDATE()) < 0 THEN 'Past' WHEN DATEDIFF(event_date, CURDATE()) = 0 THEN 'Today' ELSE 'Future' END AS status FROM events;
-- حساب أيام العمل (باستثناء عطلات نهاية الأسبوع) SELECT order_date, delivery_date, DATEDIFF(delivery_date, order_date) AS total_days, DATEDIFF(delivery_date, order_date) - (WEEK(delivery_date) - WEEK(order_date)) * 2 AS business_days_approx FROM orders; -- إضافة أيام عمل (تخطي عطلات نهاية الأسبوع) SELECT DATE_ADD(CURDATE(), INTERVAL 5 + (WEEKDAY(CURDATE() + INTERVAL 5 DAY) IN (5, 6)) * 2 DAY ) AS five_business_days_later;

DATE_FORMAT() - التنسيق المخصص

-- تنسيقات تاريخ متنوعة SELECT order_date, DATE_FORMAT(order_date, '%Y-%m-%d') AS iso_format, DATE_FORMAT(order_date, '%M %d, %Y') AS long_format, DATE_FORMAT(order_date, '%m/%d/%Y') AS us_format, DATE_FORMAT(order_date, '%d.%m.%Y') AS european_format, DATE_FORMAT(order_date, '%W, %M %D') AS day_month, DATE_FORMAT(order_date, '%Y-Q%q') AS quarter_format FROM orders; -- تنسيق: January 15, 2024 -- تنسيق: 01/15/2024 -- تنسيق: Monday, January 15th -- تنسيق: 2024-Q1
-- تنسيق الوقت SELECT created_at, DATE_FORMAT(created_at, '%H:%i:%s') AS time_24h, DATE_FORMAT(created_at, '%h:%i %p') AS time_12h, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') AS full_datetime FROM logs; -- 14:30:45 → 02:30 PM

STR_TO_DATE() - تحليل التواريخ

-- تحويل سلسلة نصية إلى تاريخ SELECT STR_TO_DATE('15-01-2024', '%d-%m-%Y') AS parsed_date, STR_TO_DATE('January 15, 2024', '%M %d, %Y') AS parsed_date2, STR_TO_DATE('2024/01/15 14:30:00', '%Y/%m/%d %H:%i:%s') AS parsed_datetime; -- استيراد البيانات بتنسيقات تاريخ متنوعة UPDATE import_table SET proper_date = STR_TO_DATE(date_string, '%m/%d/%Y') WHERE date_string REGEXP '^[0-9]{2}/[0-9]{2}/[0-9]{4}$';

تحويلات المنطقة الزمنية

-- التحويل بين المناطق الزمنية SELECT event_time, CONVERT_TZ(event_time, 'UTC', 'America/New_York') AS ny_time, CONVERT_TZ(event_time, 'UTC', 'Europe/London') AS london_time, CONVERT_TZ(event_time, 'UTC', 'Asia/Tokyo') AS tokyo_time FROM events; -- تخزين UTC، عرض في منطقة المستخدم الزمنية SELECT created_at AS utc_time, CONVERT_TZ(created_at, '+00:00', user_timezone) AS local_time FROM orders JOIN users ON orders.user_id = users.user_id;
مهم: قم دائماً بتخزين التواريخ في UTC وقم بالتحويل إلى المناطق الزمنية المحلية فقط للعرض. استخدم أعمدة DATETIME أو TIMESTAMP، وليس VARCHAR، لتخزين التاريخ الصحيح.

أجزاء التاريخ والاستخراج

-- استخراج مكونات التاريخ SELECT order_date, YEAR(order_date) AS year, MONTH(order_date) AS month, DAY(order_date) AS day, QUARTER(order_date) AS quarter, WEEK(order_date) AS week_number, DAYOFWEEK(order_date) AS day_of_week, DAYNAME(order_date) AS day_name, MONTHNAME(order_date) AS month_name, LAST_DAY(order_date) AS last_day_of_month FROM orders;
-- مكونات الوقت SELECT created_at, HOUR(created_at) AS hour, MINUTE(created_at) AS minute, SECOND(created_at) AS second, TIME(created_at) AS time_only, DATE(created_at) AS date_only FROM logs;

سيناريوهات التاريخ العملية

-- أول وآخر يوم في الشهر SELECT CURDATE() AS today, DATE_FORMAT(CURDATE(), '%Y-%m-01') AS first_day_of_month, LAST_DAY(CURDATE()) AS last_day_of_month, DATE_SUB(DATE_FORMAT(CURDATE(), '%Y-%m-01'), INTERVAL 1 DAY) AS last_day_prev_month; -- نطاقات العمر للتحليلات SELECT customer_name, birth_date, TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age, CASE WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 18 THEN 'Under 18' WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) BETWEEN 18 AND 24 THEN '18-24' WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) BETWEEN 25 AND 34 THEN '25-34' WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) BETWEEN 35 AND 44 THEN '35-44' WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) BETWEEN 45 AND 54 THEN '45-54' ELSE '55+' END AS age_group FROM customers;
-- حساب عمر العميل SELECT customer_id, MIN(order_date) AS first_order, MAX(order_date) AS last_order, DATEDIFF(MAX(order_date), MIN(order_date)) AS customer_lifetime_days, TIMESTAMPDIFF(MONTH, MIN(order_date), MAX(order_date)) AS customer_lifetime_months, COUNT(*) AS total_orders, ROUND(COUNT(*) / GREATEST(TIMESTAMPDIFF(MONTH, MIN(order_date), MAX(order_date)), 1), 2) AS orders_per_month FROM orders GROUP BY customer_id;

دمج دوال السلسلة النصية والتاريخ

-- توليد أوصاف قابلة للقراءة SELECT order_id, CONCAT( 'Order #', order_id, ' placed by ', customer_name, ' on ', DATE_FORMAT(order_date, '%M %D, %Y'), ' (', DATEDIFF(CURDATE(), order_date), ' days ago)' ) AS order_description FROM orders JOIN customers ON orders.customer_id = customers.customer_id; -- توليد عناوين URL SELECT title, LOWER( REPLACE( REPLACE( REGEXP_REPLACE(title, '[^a-zA-Z0-9 ]', ''), ' ', ' ' ), ' ', '-' ) ) AS slug FROM blog_posts; -- "My Amazing Product!" → "my-amazing-product"

مثال من العالم الحقيقي: خط أنابيب تنظيف البيانات

-- تنظيف شامل للبيانات SELECT customer_id, -- تنظيف الاسم: قص، حالة العنوان CONCAT( UPPER(SUBSTRING(TRIM(first_name), 1, 1)), LOWER(SUBSTRING(TRIM(first_name), 2)) ) AS cleaned_first_name, -- توحيد الهاتف CONCAT( '+1', REGEXP_REPLACE(phone, '[^0-9]', '') ) AS standardized_phone, -- التحقق من صحة البريد الإلكتروني وتنظيفه LOWER(TRIM(email)) AS cleaned_email, -- تحليل وتوحيد التاريخ STR_TO_DATE(birth_date_string, '%m/%d/%Y') AS birth_date, -- حساب العمر TIMESTAMPDIFF(YEAR, STR_TO_DATE(birth_date_string, '%m/%d/%Y'), CURDATE()) AS age FROM raw_customer_data WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' AND LENGTH(REGEXP_REPLACE(phone, '[^0-9]', '')) = 10;

تمرين عملي:

التحدي: اكتب استعلامات باستخدام دوال السلسلة النصية والتاريخ المتقدمة:

  1. استخراج اسم المستخدم والنطاق من جميع عناوين البريد الإلكتروني
  2. البحث عن جميع الطلبات التي تم تقديمها في عطلات نهاية الأسبوع في العام الماضي
  3. إنشاء تقرير يعرض مدة العميل بالسنوات والأشهر

الحلول:

-- 1. تحليل البريد الإلكتروني SELECT email, SUBSTRING_INDEX(email, '@', 1) AS username, SUBSTRING_INDEX(email, '@', -1) AS domain, CONCAT( SUBSTRING(SUBSTRING_INDEX(email, '@', 1), 1, 2), '***@', SUBSTRING_INDEX(email, '@', -1) ) AS masked_email FROM customers; -- 2. طلبات عطلة نهاية الأسبوع SELECT order_id, order_date, DAYNAME(order_date) AS day_name FROM orders WHERE DAYOFWEEK(order_date) IN (1, 7) -- 1=الأحد، 7=السبت AND order_date >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR) ORDER BY order_date DESC; -- 3. مدة العميل SELECT customer_name, MIN(order_date) AS first_order, TIMESTAMPDIFF(YEAR, MIN(order_date), CURDATE()) AS years_with_us, MOD(TIMESTAMPDIFF(MONTH, MIN(order_date), CURDATE()), 12) AS additional_months, CONCAT( TIMESTAMPDIFF(YEAR, MIN(order_date), CURDATE()), ' years, ', MOD(TIMESTAMPDIFF(MONTH, MIN(order_date), CURDATE()), 12), ' months' ) AS tenure FROM customers JOIN orders ON customers.customer_id = orders.customer_id GROUP BY customers.customer_id, customer_name;

الملخص

في هذا الدرس، أتقنت:

  • SUBSTRING_INDEX() و REPLACE() و REGEXP لمعالجة السلسلة النصية
  • حسابات التاريخ باستخدام TIMESTAMPDIFF() و DATEDIFF()
  • DATE_FORMAT() و STR_TO_DATE() للتنسيق والتحليل
  • تحويلات المنطقة الزمنية باستخدام CONVERT_TZ()
  • استخراج مكونات التاريخ (YEAR، MONTH، DAY، إلخ.)
  • التطبيقات الواقعية في تنظيف البيانات وتحويلها
التالي: في الدرس الأخير من هذه الوحدة، سنتقن دوال التجميع و GROUP BY لإعداد التقارير والتحليلات المعقدة!

ES
Edrees Salih
منذ 21 ساعة

We are still cooking the magic in the way!