جعبهابزار توابع داخلی
MySQL صدها تابع دارد؛ این درس آنهایی را پوشش میدهد که هر روز لازم میشوند، بههمراه رفتارهایی که مخصوص متن فارسی و پول ریالی است.
رشتهها
SELECT
LENGTH('کاشان') AS bytes, -- 10 : تعداد بایت
CHAR_LENGTH('کاشان') AS chars, -- 5 : تعداد کاراکتر
CONCAT('فرش ', NULL) AS c1, -- NULL !
CONCAT_WS(' - ', 'کاشان', NULL, 'لچکترنج') AS c2, -- NULLها رد میشوند
SUBSTRING('KSH-1001', 5) AS num, -- 1001
LPAD(42, 6, '0') AS code, -- 000042
TRIM(' فرش ') AS t,
UPPER('ksh') AS u;
برای شمارش طول متن فارسی همیشه CHAR_LENGTH را به کار ببرید؛ LENGTH بایت میشمارد و برای هر حرف فارسی ۲ برمیگرداند.
اعداد و پول
SELECT
ROUND(48750000, -5) AS r, -- 48800000 : گرد به صد هزار ریال
TRUNCATE(123.789, 1) AS tr, -- 123.7
17 DIV 5 AS q, 17 MOD 5 AS m, -- 3 و 2
FORMAT(480000000 / 10, 0) AS toman; -- '48,000,000'
تاریخ و زمان
SELECT
NOW(), CURDATE(), CURRENT_TIME(),
DATE_ADD(CURDATE(), INTERVAL 45 DAY) AS due_date,
DATEDIFF('2025-06-01', '2025-03-21') AS days,
TIMESTAMPDIFF(MONTH, '2024-03-20', CURDATE()) AS months,
DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i') AS formatted,
LAST_DAY(CURDATE()) AS month_end;
CASE: منطق شرطی داخل کوئری
SELECT sku,
CASE
WHEN reeds IS NULL THEN 'نامشخص'
WHEN reeds >= 70 THEN 'ممتاز'
WHEN reeds >= 50 THEN 'خوب'
ELSE 'معمولی'
END AS grade,
IF(stock > 0, 'موجود', 'ناموجود') AS availability
FROM carpets
ORDER BY CASE city WHEN 'کاشان' THEN 1 WHEN 'قم' THEN 2 ELSE 3 END, sku;
CASE اولین شاخهی TRUE را برمیگرداند، پس شرطها را از خاص به عام بنویسید. ترفند ORDER BY با CASE برای ترتیب دلخواه (نه الفبایی) بسیار کاربردی است.
تاریخ شمسی
MySQL تقویم جلالی ندارد. سه راه وجود دارد:
| روش | مزیت | عیب |
|---|---|---|
| تبدیل در برنامه (jdatetime در پایتون، verta در لاراول) | ساده، دقیق | گزارشگیری ماهانهی شمسی در SQL سخت است |
| Stored Function تبدیل | در همهی کوئریها در دسترس | کند روی میلیونها ردیف، مانع ایندکس |
| جدول تقویم (هر روز یک ردیف با سال و ماه شمسی) | سریع، قابل JOIN و ایندکس | یک بار ساختن جدول |
ستونها را همیشه میلادی (DATE/DATETIME) ذخیره کنید و شمسی را فقط برای نمایش و گروهبندی بسازید. در پروژهی پایانی جدول تقویم را به کار میگیریم.
نکتههایی که کمتر کسی میداند
NOW()در طول یک دستور ثابت است، اماSYSDATE()لحظهی واقعی اجرای همان تابع را میدهد و با Replication مبتنی بر statement ناسازگار است؛ تقریباً همیشه NOW را بخواهید.ROUNDروی DECIMAL «نیمه به دور از صفر» گرد میکند اما روی FLOAT و DOUBLE به کتابخانهی C وابسته است و ممکن است 2.5 را 2 کند؛ یکی دیگر از دلایل DECIMAL برای پول.FORMAT()رشته برمیگرداند؛ مرتبسازی روی خروجی آن الفبایی است و '9,000' بعد از '10,000' میآید. فقط برای نمایش نهایی.- تقسیم بر صفر در SELECT فقط NULL و یک warning میدهد، اما در INSERT و UPDATE با sql_mode سختگیر خطاست؛ برای درصدها از
x / NULLIF(y, 0)استفاده کنید. GROUP_CONCATبهطور پیشفرض خروجی را در 1024 بایت (حدود ۵۰۰ حرف فارسی) میبُرد و فقط یک warning میدهد؛SET SESSION group_concat_max_len = 100000;را فراموش نکنید.