String funksiyalar — CONCAT, LENGTH, SUBSTRING, REPLACE, TRIM
Muammodan boshlaylik
Mijozlar bazasi eski Excel dan import qilindi. Natija:
- Ismlar:
" aziz KARIMOV ","MALIKA rahimova" - Telefonlar:
"+998 90 111-22-33","90 1112233","998901112233" - Emaillar:
"Aziz@Mail.UZ"
Ularni tozalash, bir xil formatga keltirish, chiroyli ko'rsatish kerak. Buni ilovada qatorma-qator qilish mumkin — yoki bitta SQL so'rov bilan butun jadvalda.
Birlashtirish: CONCAT
SELECT CONCAT(ism, ' (', shahar, ')') AS korinish FROM mijozlar;
-- Aziz Karimov (Toshkent)
Tuzoq: biror argument NULL bo'lsa — butun natija NULL:
SELECT CONCAT('Tel: ', telefon) FROM mijozlar WHERE id = 3; -- NULL (Jasurning telefoni yo'q)
CONCAT_WS (with separator) — NULL larni tashlab ketadi:
SELECT CONCAT_WS(', ', ism, telefon, shahar) FROM mijozlar;
-- Aziz Karimov, +998901112233, Toshkent
-- Jasur Toshev, Toshkent ← NULL tashlab ketildi
Uzunlik: LENGTH va CHAR_LENGTH
SELECT LENGTH('Salom'), CHAR_LENGTH('Salom'); -- 5, 5
SELECT LENGTH('Салом'), CHAR_LENGTH('Салом'); -- 10, 5
SELECT LENGTH('👋'), CHAR_LENGTH('👋'); -- 4, 1
LENGTH— baytlar soniCHAR_LENGTH— belgilar soni
utf8mb4 da kirill harfi 2 bayt, emoji 4 bayt. "Ism 50 belgidan oshmasin" tekshiruvi uchun — doim CHAR_LENGTH.
Katta-kichik harf
SELECT UPPER('salom'), LOWER('SALOM'); -- SALOM, salom
MySQL da INITCAP (har so'zni bosh harf bilan) yo'q. Bitta so'z uchun:
SELECT CONCAT(UPPER(LEFT(ism, 1)), LOWER(SUBSTRING(ism, 2))) FROM mijozlar;
Bo'sh joylarni olib tashlash: TRIM
SELECT TRIM(' aziz '); -- 'aziz'
SELECT LTRIM(' aziz '); -- 'aziz '
SELECT RTRIM(' aziz '); -- ' aziz'
SELECT TRIM(BOTH '-' FROM '--kod--'); -- 'kod'
Kesib olish: SUBSTRING, LEFT, RIGHT
SELECT SUBSTRING('Toshkent shahri', 1, 8); -- 'Toshkent' — 1-belgidan 8 ta
SELECT SUBSTRING('Toshkent shahri', 10); -- 'shahri' — 10-belgidan oxirigacha
SELECT LEFT('+998901112233', 4); -- '+998'
SELECT RIGHT('+998901112233', 4); -- '2233'
[!INFO] SQL da pozitsiya 1 dan boshlanadi (dasturlash tillaridagidek 0 dan emas).
SUBSTRING_INDEX — ajratgich bo'yicha
SELECT SUBSTRING_INDEX('aziz@mail.uz', '@', 1); -- 'aziz' — birinchi @ gacha
SELECT SUBSTRING_INDEX('aziz@mail.uz', '@', -1); -- 'mail.uz' — oxirgi @ dan keyin
Email domenlari statistikasi:
SELECT SUBSTRING_INDEX(email, '@', -1) AS domen, COUNT(*) AS soni
FROM mijozlar
GROUP BY domen
ORDER BY soni DESC;
Qidirish: LOCATE, INSTR
SELECT LOCATE('@', 'aziz@mail.uz'); -- 5 — pozitsiya
SELECT LOCATE('x', 'aziz@mail.uz'); -- 0 — topilmadi
Almashtirish: REPLACE
SELECT REPLACE('+998 90 111-22-33', ' ', ''); -- '+99890111-22-33'
Telefon raqamlarini tozalash — bir nechta REPLACE ichma-ich:
SELECT REPLACE(REPLACE(REPLACE(REPLACE(telefon, ' ', ''), '-', ''), '(', ''), ')', '')
FROM mijozlar;
REGEXP_REPLACE (MySQL 8.0+)
Bitta muntazam ifoda bilan — "raqamdan boshqa hamma narsani olib tashla":
SELECT REGEXP_REPLACE('+998 (90) 111-22-33', '[^0-9]', ''); -- '998901112233'
Butun jadvalni tozalash
-- Avval ko'rib chiqish
SELECT telefon, REGEXP_REPLACE(telefon, '[^0-9]', '') AS toza FROM mijozlar;
-- Keyin yangilash
UPDATE mijozlar
SET telefon = CONCAT('+', REGEXP_REPLACE(telefon, '[^0-9]', ''))
WHERE telefon IS NOT NULL;
UPDATE mijozlar SET email = LOWER(TRIM(email));
UPDATE mijozlar SET ism = TRIM(ism);
To'ldirish: LPAD, RPAD
SELECT LPAD(42, 6, '0'); -- '000042'
SELECT CONCAT('B-', LPAD(id, 6, '0')) AS buyurtma_raqami FROM buyurtmalar;
-- B-000001, B-000002...
Shablon bo'yicha qidirish: REGEXP
LIKE dan kuchliroq:
-- O'zbekiston mobil raqami formatidagi telefonlar
SELECT telefon FROM mijozlar WHERE telefon REGEXP '^\\+998[0-9]{9}#39;;
-- Noto'g'ri formatdagilarni topish
SELECT id, telefon FROM mijozlar
WHERE telefon IS NOT NULL AND telefon NOT REGEXP '^\\+998[0-9]{9}#39;;
Boshqa foydali funksiyalar
SELECT REPEAT('-', 10); -- '----------'
SELECT REVERSE('salom'); -- 'molas'
SELECT FORMAT(1250000, 0); -- '1,250,000'
SELECT INSERT('998901112233', 6, 4, '****'); -- '99890****233' — maskalash
SELECT FIELD('b', 'a', 'b', 'c'); -- 2
Telefonni maskalab ko'rsatish (operatorlar uchun):
SELECT ism, CONCAT(LEFT(telefon, 6), '*****', RIGHT(telefon, 2)) AS telefon
FROM mijozlar WHERE telefon IS NOT NULL;
-- +99890*****33
Indeks va funksiyalar
-- ❌ Indeksdan foydalanib bo'lmaydi
SELECT * FROM mijozlar WHERE LOWER(email) = 'aziz@mail.uz';
-- ✅
SELECT * FROM mijozlar WHERE email = 'aziz@mail.uz';
Ustun funksiyaga o'ralganda MySQL indeksni ishlata olmaydi — har bir qator uchun funksiyani hisoblab, solishtiradi. Yechim: ma'lumotni yozishda tozalab saqlang (email doim kichik harfda), yoki case-insensitive collation ga tayaning (4-dars). MySQL 8 da ifoda bo'yicha indeks ham mumkin (31-dars).
Nima uchun shunday?
Nima uchun ma'lumotni yozishda tozalash kerak — o'qishda LOWER(TRIM(...)) qilsa ham bo'ladi-ku?
Chunki o'qish yozishdan yuzlab marta ko'p bo'ladi. Har bir o'qishda tozalash — har safar ortiqcha hisob va indeksdan foydalana olmaslik. Bundan tashqari, UNIQUE cheklov Aziz@Mail.UZ va aziz@mail.uz ni (binary collation da) har xil deb hisoblaydi — dublikat akkaunt paydo bo'ladi. Qoida: kirishda normallashtiring, keyin ma'lumot doim toza.
Xulosa
Eslab qoling:
CONCAT—NULLbo'lsa natijaNULL;CONCAT_WS—NULLlarni tashlaydiCHAR_LENGTH— belgilar,LENGTH— baytlarTRIM,UPPER,LOWER— tozalashSUBSTRING(s, boshi, soni)— 1 dan;SUBSTRING_INDEX— ajratgich bo'yichaREPLACE,REGEXP_REPLACE— almashtirish;REGEXP— format tekshiruviLPAD— raqamlarni nol bilan to'ldirishWHEREda ustunni funksiyaga o'ramang — indeks ishlamaydi; yozishda normallashtiring
Keyingi dars
26-dars: Number funksiyalar — ROUND, CEIL, FLOOR, MOD, ABS