SQL query'lar bo'yicha 30 ta intervyu savoli va javoblari
SQL query'larni joyida yozish oson emas. Ushbu qo'llanmada SQL query'lar bo'yicha ko'p beriladigan 30 ta intervyu savoli misollar, kod parchalari va tushuntirishlar bilan ko'rib chiqiladi.
WHERE va HAVING o'rtasida qanday farq bor?

Intervyu paytida SQL query'lar yozish yangi boshlovchilar uchun ham, tajribali dasturchilar uchun ham qiyin bo'lishi mumkin. Biroq to'g'ri tayyorgarlik va mashq bilan navbatdagi SQL query'lar bo'yicha intervyudan muvaffaqiyatli o'tishingiz mumkin.
Ushbu qo'llanmada sizni SELECT, JOIN, GROUP BY va window function'lar kabi ham asosiy, ham murakkab SQL query'lar bilan tanishtirib chiqaman. Har bir javob qisqa va tushunarli bo'lib, tushunchalarni yaxshiroq anglashingiz uchun SQL kod misollarini o'z ichiga oladi. Qo'llanma oxiriga kelib, SQL query'lar bo'yicha intervyudan muvaffaqiyatli o'tishga ancha yaxshi tayyor bo'lasiz va intervyudan tashqarida ham qo'llay oladigan mustahkam ko'nikmalarga ega bo'lasiz.
Samaraliroq o'rganishingiz va mashq qilishingiz uchun flashcard'lar to'plamini ham qo'shdim. Agar karyerangizni endi boshlayotgan bo'lsangiz, roadmap.sh'dagi SQL roadmap'ini ko'rib chiqing yoki bu mavzuni 60 soatdan kamroq vaqtda puxta o'zlashtirish uchun SQL query'lar kursimizdan o'ting!
SQL query'lar bo'yicha intervyuga tayyorgarlik
Intervyuga tayyorlanayotganda quyidagi jihatlarni yodda tuting.
- SQL asoslarini takrorlang. SQL qisqartmasi nimani anglatishini va u nima uchun ishlatilishini bilishingiz kerak.
- Ma'lumotlar bazalari va ularning SQL hamda NoSQL ma'lumotlar bazalari kabi turli xillari haqida asosiy tushunchaga ega ekaningizga ishonch hosil qiling.
- SQL ma'lumot tiplari hamda indexing, foreign key'lar, primary key'lar va boshqa asosiy ma'lumotlar bazasi tushunchalari haqida o'qib chiqing.
- Lokal ma'lumotlar bazalarida yoki HackerRank kabi onlayn platformalarda SQL query'lar yozishni mashq qiling.
- PostgreSQL, Microsoft SQL Server, MySQL, Oracle DB kabi kamida bitta relational database management system bilan tanishib chiqing.
- Umuman olganda, intervyu topshirayotgan kompaniyangiz nima bilan shug'ullanishini yaxshiroq bilish uchun u haqida ma'lumot to'plang, shuningdek, ularning faoliyatiga qiziqishingizni ko'rsatish uchun oldindan bir nechta savol tayyorlab qo'ying.
Barcha savollar va javoblar
Asosiy SQL query'lar
WHERE va HAVING o'rtasida qanday farq bor?
WHERE har qanday guruhlash yoki aggregation qo'llanishidan oldin satrlarni filtrlash uchun ishlatiladi.
Quyidagi kod parchasi WHERE'dan qanday foydalanishni ko'rsatadi. U Users jadvalidan Age qiymati 18 dan katta bo'lgan satrlarni ajratib oladi.
SELECT * FROM Users
WHERE Age > 18;
Query natijasi quyidagi jadvalga o'xshaydi.
| userId | firstName | lastName | age |
|---|---|---|---|
| 1 | John | Doe | 30 |
| 2 | Jane | Don | 31 |
| 3 | Will | Liam | 25 |
| 4 | Wade | Great | 32 |
| 5 | Peter | Smith | 27 |
HAVING esa guruhlash va aggregation bajarilgandan keyin guruhlarni filtrlash uchun ishlatiladi. U aggregate function'lar natijasiga qo'llanadi va asosan GROUP BY clause'i bilan birga ishlatiladi.
SELECT FirstName, Age FROM Users
GROUP BY FirstName, Age
HAVING Age > 30;
Yuqoridagi kod FirstName va Age ustunlarini tanlaydi, so'ng satrlarni FirstName va Age bo'yicha guruhlaydi va nihoyat yoshi 30 dan katta bo'lgan yozuvlarni oladi. Query natijasi quyidagicha ko'rinadi:
| firstName | age |
|---|---|
| Wade | 32 |
| Jane | 31 |
Jadvaldagi takroriy yozuvlarni qanday topasiz?
Takroriy yozuvlarni topish uchun avval takrorlanishni qanday mezon bo'yicha aniqlashni belgilab olishingiz kerak. Takrorlanishlarni ikki yoki undan ortiq ustunning kombinatsiyasi bo'yicha aniqlamoqchimisiz yoki bitta ustun ichidagi takrorlanishlarni qidiryapsizmi?
Quyidagi qadamlar jadvaldagi takroriy ma'lumotlarni topishga yordam beradi.
- Takroriy qiymatlarni tekshirmoqchi bo'lgan ustun(lar) bo'yicha barcha satrlarni guruhlash uchun GROUP BY clause'idan foydalaning.
- Qaysidir guruhda bittadan ortiq yozuv bor-yo'qligini tekshirish uchun HAVING buyrug'ida COUNT funksiyasidan foydalaning.
Avval bitta ustundagi takrorlanishlar bilan qanday ishlashni ko'rib chiqaylik. Users jadvalida 30 yoshli uchta foydalanuvchi bor. Takroriy qiymatlarni topish uchun GROUP BY clause'i va COUNT funksiyasidan foydalanamiz.
SELECT Age, COUNT(Age)
FROM Users
GROUP BY Age
HAVING COUNT(Age) > 1
Query natijasi quyidagicha ko'rinadi:
| age | count |
|---|---|
| 30 | 3 |
Bir nechta ustundagi (composite) takrorlanishlar bilan ishlash ham bitta ustundagi takrorlanishlar bilan ishlashga o'xshaydi.
SELECT FirstName, LastName, COUNT(*) AS dup_count
FROM Users
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Takrorlanishlarni topgach, sizdan ularni qanday o'chirishni so'rashlari mumkin. Takroriy yozuvlarni o'chiradigan query quyida Common Table Expression (CTE) va ROW_NUMBER() yordamida ko'rsatilgan.
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Age ORDER BY id) AS rn
FROM Users
)
DELETE FROM Users
WHERE id IN (
SELECT id
FROM ranked
WHERE rn > 1
);
Bu query ma'lumotlarning birinchi satrini saqlab qolgan holda barcha takroriy yozuvlarni o'chiradi.
INNER JOIN va LEFT JOIN o'rtasida qanday farq bor?
JOIN ikki yoki undan ortiq jadvaldagi ma'lumotlarni ular orasidagi o'zaro bog'liq ustun asosida birlashtiradi. Relational database management system'larda bir nechta jadvalga tarqalgan ma'lumotlarni olish kerak bo'lganda u juda foydali.
INNER JOIN ko'rsatilgan join sharti bo'yicha ikkala jadvalda ham mosligi bor satrlarnigina qaytaradi. Agar mos satrlar bo'lmasa, natija bo'sh bo'ladi. INNER JOIN'ning SQL sintaksisi quyidagi kod parchasida ko'rsatilgan.

SELECT table1.column_name1, table1.column_name2, table2.column_name1, table2.column_name2 FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name
Masalan, quyidagi ma'lumotlarga ega Users va Cities degan ikkita jadval bor:
Users jadvali
| userId | firstName | lastName | age | cityId |
|---|---|---|---|---|
| 1 | John | Doe | 30 | 1 |
| 2 | Jane | Don | 31 | 1 |
| 3 | Will | Liam | 25 | 1 |
| 4 | Wade | Great | 32 | 1 |
| 5 | Peter | Smith | 27 | 2 |
| 6 | Rich | Mond | 30 | 2 |
| 7 | Rach | Mane | 30 | 2 |
| 8 | Zach | Ridge | 30 | 3 |
Cities jadvali
| id | name |
|---|---|
| 1 | London |
| 2 | Manchester |
Aytaylik, foydalanuvchilar ro'yxatini ular yashaydigan shahar nomlari bilan birga olmoqchisiz. Buni INNER JOIN query'si yordamida qilish mumkin.
SELECT users.firstName, users.lastName, users.age, cities.name as cityName FROM users
INNER JOIN cities
ON users.cityId = cities.id
| firstName | lastName | age | cityName |
|---|---|---|---|
| John | Doe | 30 | London |
| Jane | Don | 31 | London |
| Will | Liam | 25 | London |
| Wade | Great | 32 | London |
| Peter | Smith | 27 | Manchester |
| Rich | Mond | 30 | Manchester |
| Rach | Mane | 30 | Manchester |
LEFT JOIN chap jadvaldagi (1-jadval) barcha satrlarni va o'ng jadvaldagi (2-jadval) ularga mos keladigan satrlarni qaytaradi. Agar o'ng jadvalda (2-jadval) mos satr bo'lmasa, uning o'rniga NULL qiymatlar qaytariladi. Left join'ning SQL sintaksisi quyidagi kod parchasida ko'rsatilgan.
SELECT table1.column_name1, table1.column_name2, table2.column_name1, table2.column_name2 FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name
Keling, avvalgi Users va Cities jadvallari asosidagi amaliy misolni ko'rib chiqamiz.
LEFT JOIN query'sini bajarganingizda quyidagi jadvalni olasiz.
| firstName | lastName | age | cityName |
|---|---|---|---|
| John | Doe | 30 | London |
| Jane | Don | 31 | London |
| Will | Liam | 25 | London |
| Wade | Great | 32 | London |
| Peter | Smith | 27 | Manchester |
| Rich | Mond | 30 | Manchester |
| Rach | Mane | 30 | Manchester |
| Zach | Ridge | 30 | null |
Jadvaldan ikkinchi eng yuqori maoshni topadigan query yozing
Bizda Salaries jadvali bor deylik:
| id | salary |
|---|---|
| 1 | 1000 |
| 2 | 2000 |
| 3 | 3000 |
| 4 | 4000 |
Ikkinchi eng yuqori maoshni topadigan query quyidagi kod parchasida ko'rsatilgan
SELECT DISTINCT Salary
FROM Salaries
ORDER BY Salary DESC
LIMIT 1 OFFSET 1
Query natijasi quyida ko'rsatilgan
| salary | |
|---|---|
| 1 | 3000 |
UNION va UNION ALL o'rtasida qanday farq bor?
UNION takroriy yozuvlarni olib tashlaydi, UNION ALL esa barcha takrorlanishlarni saqlab qoladi. Takrorlanishlarni olib tashlash (de-duplication) tufayli UNION UNION ALL'ga qaraganda sekinroq ishlaydi. Faqat noyob yozuvlarni olmoqchi bo'lsangiz UNION'dan, satrlar takrorlansa ham ularning hammasi kerak bo'lsa UNION ALL'dan foydalanasiz.
Index'lar nima va ular nima uchun foydali?
Ma'lumotlar bazasidagi index'lar kitoblardagi ko'rsatkichlarga o'xshaydi. Ular ma'lumotlar bazasidan ma'lumot olish tezligini oshiradi. Jadvaldan ma'lumot o'qimoqchi bo'lganingizda, index'lar jadvalning barcha satrlarini birma-bir ko'rib chiqish o'rniga to'g'ridan-to'g'ri siz qidirayotgan satrga borishga yordam beradi.

Ular SELECT query'larini yaxshilaydi, unumdorlikni oshiradi hamda saralash va filtrlashni tezlashtiradi. Shuningdek, ular data integrity'ni ta'minlaydi. Index'larning turli xillari bor, jumladan:
- B-Tree index
- Composite index
- Unique index
- Full text index
- Bitmap index
- Clustered index
- Non-clustered index
Primary key nima?
Primary key — jadvaldagi ma'lumotlar satrining noyob identifikatori. U har bir satrni yagona tarzda aniqlash uchun ishlatiladi va ikkita satr bir xil primary key'ga ega bo'lishi mumkin emas. Primary key ustuni null bo'la olmaydi. Quyidagi misolda user_id primary key hisoblanadi.
CREATE TABLE users (
user_id INT PRIMARY KEY,
name VARCHAR(100),
phoneNumber VARCHAR(100)
);
Foreign key nima?
Foreign key ikki jadval o'rtasidagi ko'prikka o'xshaydi. Bir jadvaldagi foreign key boshqa jadvaldagi primary key bo'ladi. U ikki jadvalni bir-biriga bog'lovchi vazifasini bajaradi.
Aggregation va guruhlash
GROUP BY qanday ishlaydi?
GROUP BY — ko'rsatilgan ustunda bir xil qiymatga ega satrlarni guruhlaydigan standart SQL buyrug'i. Uni COUNT, MIN, MAX va shu kabi aggregate function'lar bilan birga ishlatish kerak.

Quyidagi query GROUP BY clause'ini qanday ishlatishni ko'rsatadi:
SELECT columnName FROM Table
GROUP BY columnName
GROUP BY clause'ida bo'lmagan ustunni SELECT qilsangiz nima bo'ladi?
Agar GROUP BY clause'ida bo'lmagan ustunni SELECT qilsangiz, ustun GROUP BY clause'ida yoki aggregate function ichida bo'lishi kerakligi haqida xato chiqadi. Misol tariqasida quyidagi jadvaldan foydalanamiz.
| firstName | lastName | phoneNumber |
|---|---|---|
| John | Doe | +23410910 |
| Jack | Ray | +23410911 |
| Irene | Rotherdam | +23410911 |
Agar ma'lumotlar bazasida quyidagi query'ni ishga tushirsangiz:
SELECT firstName, phoneNumber FROM phoneNumbers
GROUP BY phoneNumber
Natijada xato chiqadi, chunki firstName GROUP BY clause'ida yo'q va aggregate function ichida ham ishlatilmagan.
Foydalanuvchilar sonini mamlakatlar bo'yicha COUNT qiladigan query yozing
Quyidagi ko'rinishdagi Users jadvali berilgan bo'lsin:
| userId | firstName | lastName | age | country |
|---|---|---|---|---|
| 1 | John | Doe | 30 | Portugal |
| 2 | Jane | Don | 31 | Belgium |
| 3 | Will | Liam | 25 | Argentina |
| 4 | Wade | Great | 32 | Denmark |
| 5 | Peter | Smith | 27 | USA |
| 6 | Rich | Mond | 30 | USA |
| 7 | Rach | Mane | 30 | Argentina |
| 8 | Zach | Ridge | 30 | Portugal |
Foydalanuvchilar sonini mamlakatlar bo'yicha COUNT qiladigan query:
SELECT country, COUNT(country) FROM users
GROUP BY country
Bu query foydalanuvchilarni mamlakat bo'yicha guruhlash uchun GROUP BY clause'idan foydalanadi, so'ng ularning sonini keyingi ustunda ko'rsatadi. Query natijasi quyidagicha ko'rinadi:
| country | count |
|---|---|
| USA | 2 |
| Portugal | 2 |
| Argentina | 2 |
| Belgium | 1 |
| Denmark | 1 |
GROUP BY'ni aggregate function'siz ishlatsangiz nima bo'ladi?
Agar GROUP BY clause'ini aggregate function'siz ishlatsangiz, bu DISTINCT buyrug'ini ishlatish bilan bir xil bo'ladi. Masalan, quyidagi buyruq:
SELECT phoneNumber FROM phoneNumbers
GROUP BY phoneNumber
quyidagiga teng:
SELECT DISTINCT phoneNumber FROM phoneNumbers
COUNT(\*) va COUNT(column_name) o'rtasida qanday farq bor?
Farqi shundaki, COUNT(*) NULL qiymatlarni ham qo'shib, ma'lumotlarning barcha satrlarini sanaydi, COUNT(column_name) esa ko'rsatilgan ustundagi faqat NULL bo'lmagan qiymatlarni sanaydi. Buni Users nomli jadval misolida ko'rib chiqamiz.
| userId | firstName | lastName | age | country |
|---|---|---|---|---|
| 1 | John | Doe | 30 | Portugal |
| 2 | Jane | Don | 31 | Belgium |
| 3 | Zach | Ridge | 30 | Norway |
| 4 | null | Tom | 25 | Denmark |
Agar COUNT(*) ishlatsangiz, natija 4 bo'ladi, COUNT(firstName) ishlatsangiz esa null qiymatni hisobga olmasdan 3 ni qaytaradi.
Subquery'lar va ichma-ich mantiq
Subquery va JOIN o'rtasida qanday farq bor?
Subquery — boshqa query ichida joylashgan query. U murakkab mantiq talab qiladigan query'larda ishlatiladi. Subquery natijasidan boshqa query uchun foydalanmoqchi bo'lsangiz, subquery'lardan foydalaning. Quyidagi misolda subquery qavs ichida berilgan.

SELECT firstName,
(SELECT COUNT(*)
FROM cities
WHERE cities.id = users.city_id) AS cityCount
FROM users;
JOIN esa ikki yoki undan ortiq jadvalni ular orasidagi o'zaro bog'liq ustunlar asosida birlashtiradi. Bog'liq ustun odatda foreign key bo'ladi. Turli jadvallardagi o'zaro bog'liq ma'lumotlarni bir joyga jamlamoqchi bo'lsangiz, JOIN'lardan foydalaning. Quyidagi kod JOIN'dan qanday foydalanishni ko'rsatadi.
SELECT firstName, COUNT(*) FROM users
JOIN cities ON users.city_id = cities.id
Quyidagi holatlarda JOIN subquery'dan tezroq ishlaydi:
- Bir nechta jadvaldan ma'lumotlarni query qilayotganingizda.
- Index'langan ustunlar bo'yicha filtrlayotganingizda yoki join qilayotganingizda.
O'rtacha maoshdan ko'proq maosh oladigan xodimlarni topadigan query yozing
id, name va salary ustunlariga ega, quyidagi ko'rinishdagi Employees jadvali berilgan bo'lsin:
| id | name | salary |
|---|---|---|
| 1 | Irene | 1000 |
| 2 | Peter | 1230 |
| 3 | Raymond | 1450 |
| 4 | Henry | 1790 |
| 5 | Naomi | 2350 |
| 6 | Bridget | 2000 |
| 7 | Emily | 2500 |
| 8 | Great | 3000 |
| 9 | Mercedes | 2750 |
| 10 | Zoe | 2900 |
O'rtacha maoshdan ko'proq maosh oladigan xodimlarni topadigan query:
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
| id | name | salary |
|---|---|---|
| 5 | Naomi | 2350 |
| 7 | Emily | 2500 |
| 8 | Great | 3000 |
| 9 | Mercedes | 2750 |
| 10 | Zoe | 2900 |
Correlated subquery qanday ishlashini tushuntiring
Correlated subquery — outer query'dagi qiymatga bog'liq bo'lgan subquery. Bu shuni anglatadiki, subquery outer query'da tanlanishi mumkin bo'lgan har bir satr uchun alohida hisoblanadi. Quyida correlated subquery'ga misol keltirilgan.
SELECT name, country_id, salary
FROM employees em
WHERE salary > (
SELECT AVG(salary) FROM employees
country_id = em.country_id);
Yuqoridagi kod:
- Outer query'ni jadvalning har bir satri bo'ylab ishga tushiradi.
employeesjadvalidancountry_idqiymatini oladi.- Qolgan satrlar bo'ylab yurib, xuddi shu hisob-kitobni bajaradi.
Shu sababli jadvaldagi ma'lumotlar ko'paygan sari unumdorlik pasayib boradi.
Agar har bir satrga xos amallarni bajarmoqchi bo'lsangiz yoki biror amalni JOIN yoki boshqa aggregate function'lar yordamida bajara olmasangiz, correlated subquery'dan foydalaning.
Subquery'da qachon IN o'rniga EXISTS ishlatish kerak?
EXISTS ham, IN ham subquery'larda natijalarni filtrlash uchun ishlatiladi, lekin qanday ishlatilishiga qarab ular turli vazifalarni bajaradi.
EXISTS'dan quyidagi holatlarda foydalanish kerak:
- Haqiqiy qiymatlarni emas, balki satr mavjud yoki yo'qligini tekshirmoqchi bo'lsangiz.
- Subquery correlated query bo'lsa.
- Subquery ko'p satr qaytarsa-yu, sizga faqat birinchi moslik kerak bo'lsa.
IN'dan quyidagi holatlarda foydalanish kerak:
- Ustunni qiymatlar ro'yxati bilan solishtirayotganingizda.
- Subquery kichik yoki o'zgarmas (static) ro'yxat qaytarsa.
Subquery'larni bir necha daraja chuqurlikda ichma-ich joylashtirish mumkinmi?
Ha, murakkab mantiqni amalga oshirmoqchi bo'lsangiz, subquery'larni bir necha daraja chuqurlikda ichma-ich joylashtirishingiz mumkin. Nested subquery — boshqa subquery ichida joylashgan subquery bo'lib, subquery'lardan iborat qatlamlarni hosil qiladi. Ko'pgina SQL engine'lar subquery'larning bir nechta qatlamiga ruxsat beradi, biroq bu kodning o'qilishini qiyinlashtiradi va unumdorlikni pasaytiradi.
Window function'lar va murakkab query'lar
Window function nima?
Window function — joriy satrga bog'liq bo'lgan muayyan satrlar to'plami ustida amallar bajarish imkonini beradigan funksiya. Butun dataset ustida hisob-kitob qiladigan aggregate function'lardan farqli o'laroq, window function'lar ma'lumotlarning bir qismi (subset) ustida amal bajara oladi. Bunday hisob-kitoblar asl dataset'ni o'zgartirmagan holda aggregation, ranking va kumulyativ yig'indilarni hisoblash uchun qo'llaniladi.
Running total'ni hisoblaydigan query yozing
Bu query uchun misol sifatida Sales jadvalidan foydalanamiz. Unda uchta ustun bor: id, hafta kunini bildiruvchi day va AQSh dollarida sotilgan summani bildiruvchi amount. Jadval quyidagicha ko'rinadi:
| id | day | amount |
|---|---|---|
| 1 | Monday | 200 |
| 2 | Tuesday | 300 |
| 3 | Wednesday | 600 |
| 4 | Thursday | 390 |
| 5 | Friday | 900 |
Running total'ni hisoblaydigan query:
SELECT
id,
sale_date,
amount,
SUM(amount) OVER (ORDER BY sale_date) AS running_total
FROM
sales;
Bu query har bir satr uchun summani qo'shib borish va running total'ni saqlash maqsadida OVER window function'idan foydalanadi. U har bir kun uchun summani olib, avvalgi yig'indilarga qo'shadi. Query natijasi quyidagicha ko'rinadi:
| id | day | amount | running_total |
|---|---|---|---|
| 1 | Monday | 200 | 200 |
| 2 | Tuesday | 300 | 500 |
| 4 | Thursday | 390 | 1100 |
| 3 | Wednesday | 600 | 1490 |
| 5 | Friday | 900 | 2390 |
Rasmdan ko'rinib turibdiki, oxirgi ustun running_total, bo'lib, u joriy kunning summasini olib, joriy qiymatini hosil qilish uchun uni avvalgi qiymatiga qo'shadi.
RANK(), DENSE_RANK() va ROW_NUMBER() o'rtasida qanday farq bor?
RANK() funksiyasi har bir satrga o'sish yoki kamayish tartibiga ko'ra rank beradi. Agar qiymatlar bir xil bo'lsa, ularga bir xil o'rin beradi va keyingi rank uchun navbatdagi sonni tashlab ketadi. Masalan, ikkita satr teng qiymatga ega bo'lib, ikkalasiga ham 1-rank berilgan bo'lsa, keyingi rank 2 emas, 3 bo'ladi.

RANK() funksiyasini ko'rsatish uchun oldingi savoldagi Sales jadvalidan foydalanamiz. Summa bo'yicha tartiblab rank beradigan query quyidagicha:
SELECT
id,
day,
amount,
RANK() OVER (ORDER BY amount DESC) AS amount_rank
FROM
sales;
Natija quyidagi rasmda ko'rsatilgan. Ko'rib turganingizdek, 900 summasi birinchi rank'ni, 200 esa eng past rank'ni olgan. Shuningdek, ikkita qiymat bir xil rank'ga ega bo'lgani uchun 2 va 4-rank'lar orasida oraliq paydo bo'lgan. Bundan eng ko'p savdo juma kuni, eng kami esa dushanba kuni bo'lganini ham bilib olish mumkin.
| id | day | amount | amount_rank |
|---|---|---|---|
| 5 | Friday | 900 | 1 |
| 3 | Wednesday | 600 | 2 |
| 6 | Saturday | 600 | 2 |
| 4 | Thursday | 390 | 4 |
| 2 | Tuesday | 300 | 5 |
| 1 | Monday | 200 | 6 |
DENSE_RANK() funksiyasi satrlarga rank berishi jihatidan RANK()'ga o'xshaydi, ammo farqi shundaki, ikki yoki undan ortiq teng qiymat bo'lganda DENSE_RANK oraliq qoldirmaydi. Buni yuqoridagi Sales jadvali misolida ko'rsatamiz. Query quyida keltirilgan.
SELECT
id,
day,
amount,
DENSE_RANK() OVER (ORDER BY amount DESC) AS amount_rank
FROM
sales;
Natija quyida ko'rsatilgan. Ko'rib turganingizdek, RANK funksiyasidagidan farqli ravishda rank'lar orasida oraliq yo'q.
| id | day | amount | amount_rank |
|---|---|---|---|
| 5 | Friday | 900 | 1 |
| 3 | Wednesday | 600 | 2 |
| 6 | Saturday | 600 | 2 |
| 4 | Thursday | 390 | 3 |
| 2 | Tuesday | 300 | 4 |
| 1 | Monday | 200 | 5 |
ROW_NUMBER siz ko'rsatgan tartibga qarab har bir satrga noyob raqam beradi. U hech bir raqamni tashlab ketmaydi: teng qiymatlar bo'lsa ham, ularga turli raqamlar beradi. Bu jihatdan u teng qiymatlarga bir xil rank beradigan RANK va DENSE_RANK funksiyalaridan farq qiladi.
Misol uchun yana o'sha Sales jadvalidan foydalanamiz. Quyidagi query ROW_NUMBER funksiyasidan qanday foydalanishni ko'rsatadi.
SELECT
id,
day,
amount,
ROW_NUMBER() OVER (ORDER BY amount DESC) AS rowNumber
FROM
sales;
Natija quyidagi rasmda ko'rsatilgan. Ko'rib turganingizdek, rownumber ustuni ortib boradi va bir xil qiymatlar bo'lsa ham, har biriga shunchaki noyob satr raqami beriladi.
| id | day | amount | amount_rank |
|---|---|---|---|
| 5 | Friday | 900 | 1 |
| 3 | Wednesday | 600 | 2 |
| 6 | Saturday | 600 | 3 |
| 4 | Thursday | 390 | 4 |
| 2 | Tuesday | 300 | 5 |
| 1 | Monday | 200 | 6 |
SQL'da LAG() va LEAD() nima? Ulardan foydalanishga misol keltiring
LAG() va LEAD() — ko'rsatilgan satrdan oldingi va keyingi satrlardagi ma'lumotlarni olish uchun ishlatiladigan window function'lar. Ularni positional SQL function'lar deb ham atash mumkin.
LAG() joriy satrdan oldingi satrlarda saqlangan qiymatga murojaat qilish imkonini beradi. Bu satr bevosita oldingi satr yoki bir necha satr oldingisi bo'lishi mumkin. Sintaksisini ko'rib chiqamiz:
LAG(column_name, offset, default_value)
U uchta argument qabul qiladi.
- column_name: oldingi satrdan qaysi ustun qiymatini olishni belgilaydi.
- offset: ixtiyoriy argument bo'lib, necha satr orqaga qarash kerakligini belgilaydi. Standart qiymati 1.
- default_value: oldingi satr mavjud bo'lmaganda beriladigan qiymat. U ixtiyoriy, standart qiymati NULL.
LAG() funksiyasini Sales jadvali misolida ko'rsatamiz. Bu query oldingi kungi savdoni topish uchun ishlatiladi. LAG() o'tgan voqealar bo'yicha hisobotlar tayyorlashda foydali.
| id | day | amount |
|---|---|---|
| 1 | Monday | 200 |
| 2 | Tuesday | 300 |
| 3 | Wednesday | 600 |
| 4 | Thursday | 390 |
| 5 | Friday | 900 |
| 6 | Saturday | 600 |
SELECT
id,
day,
amount,
LAG(amount) OVER (ORDER BY id) AS previous_day_sales
FROM
sales;
Query natijasi quyidagicha ko'rinadi:
| id | day | amount | previous_day_sales |
|---|---|---|---|
| 1 | Monday | 200 | null |
| 2 | Tuesday | 300 | 200 |
| 3 | Wednesday | 600 | 300 |
| 4 | Thursday | 390 | 600 |
| 5 | Friday | 900 | 390 |
| 6 | Saturday | 600 | 900 |
LEAD() funksiyasi joriy satrdan keyingi satrlardagi ma'lumotlarni olish uchun ishlatiladi. Uning sintaksisi LAG() funksiyasinikiga o'xshaydi. Undan oldinga qarab, kelajakdagi trend'larni prognoz qilishda foydalanish mumkin.
LEAD() funksiyasidan foydalanilgan query quyida ko'rsatilgan.
SELECT
id,
day,
amount,
LEAD(amount) OVER (ORDER BY id) AS previous_day_sales
FROM
sales;
| id | day | amount | previous_day_sales |
|---|---|---|---|
| 1 | Monday | 200 | 300 |
| 2 | Tuesday | 300 | 600 |
| 3 | Wednesday | 600 | 390 |
| 4 | Thursday | 390 | 900 |
| 5 | Friday | 900 | 600 |
| 6 | Saturday | 600 | null |
Har bir foydalanuvchi uchun sanalar ketma-ketligidagi bo'shliqlarni qanday aniqlaysiz?
Har bir foydalanuvchi uchun sanalar ketma-ketligidagi bo'shliqlarni aniqlashda LAG() funksiyasidan foydalanasiz. Har bir sanani oldingisi bilan solishtirib, ular orasidagi farq 1 dan katta yoki katta emasligini tekshirasiz.
Bo'shliqlarni qanday aniqlashni ko'rsatish uchun ClockIns jadvalidan foydalanamiz. Jadvalda ikkita ustun bor: userId va clockInDate. Ular mos ravishda foydalanuvchining identifikatsiya raqamini va foydalanuvchi kirish kartasi orqali binoga kirib, kelganini qayd etgan sanani bildiradi. Jadval quyidagicha ko'rinadi:
| userId | clockInDate |
|---|---|
| 1 | 2025-01-01 |
| 1 | 2025-01-02 |
| 1 | 2025-01-05 |
| 1 | 2025-01-06 |
| 2 | 2025-01-06 |
| 2 | 2025-01-06 |
| 2 | 2025-01-07 |
| 3 | 2025-01-02 |
| 3 | 2025-01-04 |
| 3 | 2025-01-06 |
| 3 | 2025-01-07 |
Har bir foydalanuvchi bo'yicha bo'shliqlarni topadigan query quyidagicha ko'rinadi:
WITH clockInGaps AS (
SELECT
userid,
clockInDate,
LAG(clockInDate) OVER (PARTITION BY userId ORDER BY clockInDate) AS previousClockInDate
FROM
clockIns
)
SELECT
userId,
previousClockInDate AS gapStart,
clockInDate AS gapEend,
clockInDate - previousClockInDate - 1 AS gapDays
FROM clockInGaps
WHERE clockInDate - previousClockInDate > 1
ORDER BY userId, gapStart;
Yuqoridagi kod avval clockInGaps ifodasini yaratadi: u har bir foydalanuvchi va uning clockInDate qiymatlarini query qiladi hamda har bir foydalanuvchi uchun oldingi sanani olishda LAG funksiyasidan foydalanadi. So'ng asosiy query har bir satrni filtrlab, joriy sana va oldingi sana orasidagi bo'shliqlarni topadi. Query natijasi quyidagicha ko'rinadi:
| userId | gapStart | gapEnd | gapDays |
|---|---|---|---|
| 1 | 2025-01-02 | 2025-01-05 | 2 |
| 2 | 2025-01-07 | 2025-01-10 | 2 |
| 3 | 2025-01-02 | 2025-01-04 | 1 |
| 3 | 2025-01-04 | 2025-01-06 | 1 |
NTILE() funksiyasi nima qiladi va u ma'lumotlarni tahlil qilishda qanday foydali bo'lishi mumkin?
NTILE() — satrlarni oldindan belgilangan miqdordagi taxminan teng guruhlarga ajratadigan window function. Bu ma'lumotlaringizni o'zingiz belgilagan mezonlar asosida turli to'plamlarga bo'lishga o'xshaydi. Masalan, sizda talabalarning 1 dan 100 gacha bo'lgan ballari bor deylik; NTILE() funksiyasi yordamida bu ballarni turli guruhlarga yoki bucket'larga ajratishingiz mumkin.
NTILE() funksiyasining sintaksisi:
NTILE(n) OVER (ORDER BY some_column)
- n: satrlarni nechta guruhga ajratmoqchi ekaningizni bildiradi.
- ORDER BY: funksiya qo'llanadigan har bir guruhdagi satrlar tartibini belgilaydi.
Keling, Scores jadvali misolida amaliy namunani ko'rib chiqamiz. Jadvalda talabalarning testda olgan ballari saqlanadi. NTILE() funksiyasidan qanday foydalanishni ko'ramiz.
| userId | score |
|---|---|
| 1 | 78 |
| 2 | 70 |
| 3 | 90 |
| 4 | 98 |
| 5 | 60 |
| 6 | 88 |
| 7 | 100 |
| 8 | 66 |
NTILE() funksiyasidan foydalanilgan query quyidagicha ko'rinadi:
SELECT
id,
score,
NTILE(3) OVER (ORDER BY score DESC) AS category
FROM scores;
| userId | score | category |
|---|---|---|
| 7 | 100 | 1 |
| 4 | 98 | 1 |
| 3 | 90 | 1 |
| 6 | 88 | 2 |
| 1 | 78 | 2 |
| 2 | 70 | 2 |
| 8 | 66 | 3 |
| 5 | 60 | 3 |
NTILE() funksiyasi ma'lumotlar tahlilida foydali, chunki u dataset'dagi outlier'larni aniqlashi va ma'lumotlarning histogram'larini yaratishi mumkin. Shuningdek, u ma'lumotlar taqsimoti uchun percentile va quartile'larni ham hosil qila oladi.
Optimallashtirish va keng tarqalgan xatolar
Sekin ishlayotgan query'larni qanday optimallashtirasiz?
Sekin ishlayotgan query'larni optimallashtirish uchun avval nimani optimallashtirish kerakligini bilish maqsadida query'ni tahlil qilishingiz kerak. Query'ga qarab turli optimallashtirishlarni bajarish mumkin. Ulardan ba'zilari:
-
Index'lardan samarali foydalanish: Index'lar ma'lumotlar bazasiga muayyan mezonlarga mos yozuvlarni tez topish imkonini berib, query'larni tezlashtiradi. Indexing — bir yoki bir nechta ustun qiymatlarini noyob qiymatga moslashtirish jarayoni bo'lib, u qidiruv mezoniga mos satrlarni topishni osonlashtiradi. WHERE, JOIN va ORDER BY clause'larida tez-tez ishlatiladigan ustunlarga index yaratishingiz mumkin. Biroq juda ko'p index yaratish ma'lumot kiritish, yangilash va o'chirish amallarini sekinlashtirishi mumkinligini yodda tuting.
-
SELECT *'dan qoching: SELECT * statement'idan foydalanish query unumdorligini pasaytirishi mumkin, chunki u jadvaldagi barcha ustunlarni, jumladan query uchun kerak bo'lmaganlarini ham qaytaradi. Optimal unumdorlik uchun query'da faqat sizga kerak bo'lgan ustunlarni tanlang. Shuning uchun barcha ustunlarni tanlaydigan query'ni ko'rganingizda, bu ustunlarning hammasi haqiqatan kerakmi va query zanjirida keyinchalik ishlatiladimi, tekshirib ko'ring.
-
Subquery'lardan qoching: Subquery'lar, ayniqsa
WHEREyokiHAVINGclause'larida ishlatilganda, query unumdorligini pasaytiradi. Iloji boricha subquery'lardan qochib, ularning o'rniga JOIN'lar yoki boshqa usullardan foydalaning. -
Stored procedure'lardan foydalaning: Stored procedure'lar — ma'lumotlar bazasida saqlanadigan, oldindan kompilyatsiya qilingan SQL statement'lari bo'lib, ularni ilovadan yoki to'g'ridan-to'g'ri query'dan chaqirish mumkin. Stored procedure'lardan foydalanish ma'lumotlar bazasi va ilovangiz o'rtasida uzatiladigan ma'lumotlar hajmini kamaytirish orqali query unumdorligini oshiradi, shuningdek, SQL statement'larini kompilyatsiya qilishga ketadigan vaqtni tejaydi.
Nima uchun production kodda SELECT \* ishlatishdan qochish kerak?
Production kodingizda quyidagi sabablarga ko'ra SELECT * ishlatishdan iloji boricha qoching:
-
IO ortadi: SELECT * ishlatganingizda keraksiz ma'lumotlar ham qaytarilishi mumkin. Jadvaldagi barcha ma'lumotlarni o'qiyotganingiz sababli bu ma'lumotlar bazasi darajasida Input/Output sikllarining ko'payishiga olib keladi. Bu ta'sir ma'lumotlari ko'p bo'lgan jadvalda yanada sezilarli bo'ladi va hatto query'ni sekinlashtiradi.
-
Tarmoq trafigi ortadi: SELECT * mijozga keragidan ko'proq ma'lumot qaytaradi, bu esa zarur bo'lganidan ko'proq network bandwidth sarflaydi. Bandwidth sarfining oshishi ma'lumotlarning mijoz ilovasiga yetib borishini sekinlashtiradi va ilova unumdorligiga ta'sir qiladi.
-
Ilova ko'proq xotira talab qiladi: Ko'p ma'lumot qaytarilishi ilovangizdan foydalanmasligingiz mumkin bo'lgan keraksiz ma'lumotlarni saqlash uchun ko'proq xotira talab qiladi va bu ilova unumdorligiga ta'sir qiladi.
-
Kodni qo'llab-quvvatlash qiyinlashadi: SELECT * ishlatish kodni qo'llab-quvvatlashni murakkablashtiradi. Agar jadval tuzilmasi ustun qo'shish, olib tashlash yoki qayta nomlash orqali o'zgarsa, SELECT * ishlatadigan query'lar kutilmaganda buzilishi mumkin. Ma'lumotlar bazasi schema'sidagi ehtimoliy o'zgarishlarga chidamli bo'lish uchun ma'lumot olmoqchi bo'lgan ustunlarni aniq ko'rsating.
Index'larning yo'qligi qanday oqibatlarga olib keladi?
Index'larning yo'qligi, ayniqsa ma'lumotlar ko'paygan sari, query'lar unumdorligiga ta'sir qilishi mumkin. Index'lar yo'qligining asosiy oqibatlari quyida keltirilgan:
- Sekin query'lar: Index'lar bo'lmasa, har bir o'qish query'si mos satrlarni topish uchun butun jadvalni ko'rib chiqadi. Jadvaldagi ma'lumotlar ko'paygani sari bu holat yomonlashib boradi.
- Locking va concurrency muammolari: Index'siz jadvalni skanerlash ko'proq vaqt oladi, jadvalning lock qilinishi esa boshqa query'larning bajarilishiga to'sqinlik qilib, ilova unumdorligiga ta'sir qilishi mumkin.
- Samarasiz join'lar: Join key'larida index bo'lmagan jadvallar ustidagi join'lar juda sekin ishlaydi va query unumdorligini yomonlashtiradi.
- Yomon foydalanuvchi tajribasi: Index'larning yo'qligi ilovalaringizda foydalanuvchi tajribasining yomonlashishiga olib kelishi mumkin. Bu sahifalarning sekin yuklanishiga, ma'lumotlar bazasidan ma'lumot olinayotganda ilovaning qotib qolishiga sabab bo'lishi mumkin.
SARGable query nima?
SARGable — Search Argumentable query degan ma'noni anglatadi: bunday query index'lardan foydalanadi va samarali bajariladi. Agar query SARGable bo'lsa, database engine index'lar yordamida satrlarni tez topadi, butun jadvalni skanerlashdan qochadi va query unumdorligini oshiradi.
GROUP BY'dan foydalanishda qanday xatolar ko'p uchraydi?
GROUP BY clause'idan foydalanishda ko'p uchraydigan xatolar quyidagilar:
- GROUP BY clause'ida bo'lmagan, aggregation qilinmagan ustunlarni tanlash: Bu yangi boshlovchilar ham, tajribali mutaxassislar ham ko'p yo'l qo'yadigan xato. Bunday query'ga misol:
SELECT day, amount FROM Sales
GROUP BY day
Yuqoridagi query'da amount ustuni GROUP BY clause'iga kirmagan, shuning uchun u GROUP BY clause'ida bo'lishi kerakligi haqida xato chiqadi. Buni tuzatish uchun amount ustuniga aggregate function qo'llash kerak.
SELECT day, MAX(amount) FROM Sales
GROUP BY day
- Aggregate function'lardan foydalanmaslik:
GROUP BY'ni aggregate function'larsiz ishlatish ham ko'p uchraydigan xato.GROUP BYodatdaMAX,MIN,COUNTkabi aggregate function'lar bilan birga ishlatiladi. - Bir nechta ustun bo'yicha guruhlash: Ko'p ustunlar bo'yicha guruhlash query'ni ma'nosiz qilib qo'yishi mumkin. Ko'p ustunlar bo'yicha guruhlash odatiy hol emas, shunday holat yuz berganda esa haqiqatan ham shu ustunlar bo'yicha guruhlash kerakmi yoki yo'qligini tekshirib ko'ring.
Nima uchun NOT IN NULL'lar bilan kutilmagan natijalarga olib kelishi mumkin?
NULL noma'lum qiymat bo'lgani uchun, mumkin bo'lgan qiymatlar ro'yxatida NULL bo'lgan NOT IN query'si NULL qiymat keltirib chiqaradigan noma'lum natija tufayli doim 0 ta yozuv qaytaradi. SQL qiymat o'sha ro'yxatda yo'qligini aniq hal qila olmaydi.
Buni quyidagi ko'rinishdagi Sales jadvali misolida ko'rsatamiz:
| id | day | amount |
|---|---|---|
| 1 | Monday | 200 |
| 2 | Tuesday | 300 |
| 3 | Wednesday | 600 |
| 4 | Thursday | 390 |
| 5 | Friday | 900 |
| 6 | Saturday | 600 |
Quyidagi query'ni ishga tushirsangiz, u bo'sh natija qaytaradi, chunki hech narsa NULL'ga teng ham, teng emas ham bo'lmaydi va SQL qiymat ro'yxatda yo'qligini aniqlay olmaydi.
SELECT * from sales
WHERE amount NOT IN (200, 300, 600, NULL);