Chapterبەش 9 · Lectureوانە 9.4
SQL Functions, Aggregates and GROUP BYکردارەکانی SQL، کردارەکانی کۆکردنەوە و GROUP BY
Make SQL calculate: single-row functions for numbers (ROUND, POWER, MOD), text (UPPER, LENGTH and CHAR_LENGTH, SUBSTRING, INSTR, TRIM, CONCAT) and dates (YEAR, MONTHNAME, DAYNAME); the aggregate functions COUNT, SUM, AVG, MIN and MAX; GROUP BY for one answer per group, HAVING to keep or drop groups, and the order in which SQL reads a query — with the differences between MySQL, MariaDB and SQLite.
وا لە SQL بکە ژماردن بکات: بۆ ژمارە (ROUND، POWER، MOD)، دەق (UPPER، LENGTH و CHAR_LENGTH، SUBSTRING، INSTR، TRIM، CONCAT) و بەروار (YEAR، MONTHNAME، DAYNAME)؛ COUNT، SUM، AVG، MIN و MAX؛ بۆ یەک وەڵام بۆ هەر گرووپێک، بۆ هێشتنەوە یان لابردنی گرووپەکان و ئەو ڕیزبەندییەی SQL پێ دەخوێنێتەوە — لەگەڵ جیاوازییەکانی نێوان MySQL، MariaDB و SQLite.
What you will learnچی فێر دەبیت
- Tell single-row functions from aggregate functions, and say where each kind may be used.
- Use numeric functions — ROUND with negative places, POWER, MOD, FLOOR and CEIL — in SELECT and UPDATE.
- Use text functions, explain why LENGTH and CHAR_LENGTH differ for Kurdish text, and split an e-mail address with INSTR and SUBSTRING.
- Take dates apart with YEAR, MONTH, DAY, MONTHNAME and DAYNAME, and use a date function in WHERE.
- Predict COUNT(*), COUNT(column), COUNT(DISTINCT), SUM, AVG, MIN and MAX, also with NULLs, on text and dates, and when no row matches.
- Group rows with GROUP BY, keep or drop groups with HAVING, and write queries that MySQL 8.4 accepts with ONLY_FULL_GROUP_BY.
- Explain the logical order FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, LIMIT, and use it to find mistakes.
- لە جیا بکەیتەوە و بڵێیت هەر جۆرێکیان لە کوێ بەکار دێت.
- — ROUND بە شوێنی سالب، POWER، MOD، FLOOR و CEIL — لە SELECT و UPDATE بەکار بهێنیت.
- بەکار بهێنیت، ڕوون بکەیتەوە بۆچی LENGTH و CHAR_LENGTH بۆ دەقی کوردی جیاوازن و بە INSTR و SUBSTRING لەت بکەیت.
- بەروار بە YEAR، MONTH، DAY، MONTHNAME و DAYNAME بکەیتە بەش و بەروار لە WHERE بەکار بهێنیت.
- پێشبینیی COUNT(*)، COUNT(column)، COUNT(DISTINCT)، SUM، AVG، MIN و MAX بکەیت، لەگەڵ NULL، لەسەر دەق و بەروار و کاتێک هیچ یەک ناگرێتەوە.
- بە GROUP BY گرووپ بکەیت، گرووپەکان بە HAVING بهێڵیتەوە یان لایان ببەیت و بنووسیت کە MySQL 8.4 لەگەڵ ONLY_FULL_GROUP_BY وەری بگرێت.
- ڕیزبەندیی لۆجیکیی FROM، WHERE، GROUP BY، HAVING، SELECT، DISTINCT، ORDER BY، LIMIT ڕوون بکەیتەوە و بۆ دۆزینەوەی هەڵە بەکاری بهێنیت.
SQL functions: two kindsکردارەکانی SQL: دوو جۆر
An SQL does one job and gives back a value — exactly the idea of a function in PHP (what is a function?). MySQL has hundreds of . You call one by its name with its arguments in brackets: ROUND(2912.564, 1) gives 2912.6.
SQL یەک کار دەکات و نرخێک دەگەڕێنێتەوە — ڕێک هەمان بیرۆکەی لە PHP (کردار چییە؟). MySQL سەدان هەیە. بە ناوەکەی و لە ناو کەوانەدا بانگی دەکەیت: ROUND(2912.564, 1) 2912.6 دەدات.
All examples run on the shop database of the previous lesson (our example: a phone and computer shop). When MySQL and SQLite give different answers, both are shown.
هەموو نموونەکان لەسەر دوکانەکەی وانەی پێشوو جێبەجێ دەکرێن (نموونەکەمان: دوکانێکی مۆبایل و کۆمپیوتەر). هەر کاتێک MySQL و SQLite وەڵامی جیاواز بدەن، هەردووکیان پیشان دەدرێن.
SQL functions come in two kinds, and the difference is about how many rows go in:
SQL دوو جۆرن و جیاوازییەکەیان لە ژمارەی ئەو کە دەچنە ناویانەوە:
- A works on one row at a time and gives one result for every row:
UPPER(name)turns every name into capitals. There are three groups: numeric, text and date functions. - An takes many rows and gives one result:
MAX(price_iqd)reads every price and answers with the largest. WithGROUP BYit gives one result per group.
- هەر جارە لەسەر یەک کار دەکات و بۆ هەموو یەک ئەنجام دەدات:
UPPER(name)هەموو ناوێک دەکاتە پیتی گەورە. سێ گرووپی هەیە: ژمارەیی، دەقی و بەروار. - چەندین وەردەگرێت و یەک ئەنجام دەدات:
MAX(price_iqd)هەموو قیمەتێک دەخوێنێتەوە و بە گەورەترینیان وەڵام دەداتەوە. لەگەڵGROUP BYبۆ هەر گرووپێک یەک ئەنجام دەدات.
SQL functions: two kindsکردارەکانی SQL: دوو جۆر
Where each kind can be usedهەر جۆرێک لە کوێ بەکار دێت
The two kinds differ in how many rows go in, how many results come out, and where in a query they may stand:
دوو جۆرەکە لەمانەدا جیاوازن: چەند دەچێتە ناویان، چەند ئەنجام دەردەچێت و لە کوێی دەتوانن بێن:
| Single-row (scalar) function | Aggregate (multiple-row) function | |
|---|---|---|
| Works onکار دەکات لەسەر | one row at a timeهەر جارە یەک | a group of rows (the whole table if there is no GROUP BY)گرووپێک (هەموو ئەگەر GROUP BY نەبێت) |
| Givesدەدات | one result per rowیەک ئەنجام بۆ هەر | one result per groupیەک ئەنجام بۆ هەر گرووپێک |
| Can be used inلە کوێ بەکار دێت | SELECT, WHERE, ORDER BY (and GROUP BY) | SELECT, HAVING, ORDER BY |
| Examplesنموونە | ROUND, UPPER, SUBSTRING, YEAR, DAYNAME | COUNT, SUM, AVG, MIN, MAX |
Numeric functionsکردارە ژمارەییەکان
| Function | What it doesچی دەکات | Exampleنموونە | MySQL answerوەڵامی MySQL |
|---|---|---|---|
ROUND(n, d) | rounds n to d decimal places; without d, to a whole numbern بۆ d شوێنی دوای خاڵ خڕ دەکاتەوە؛ بەبێ d بۆ | ROUND(2912.564, 1) | 2912.6 |
d may be negative: −1 rounds to tens, −3 to thousandsd دەکرێت سالب بێت: −1 بۆ دەیان خڕ دەکاتەوە، −3 بۆ هەزاران | ROUND(342.9234, -1) | 340 | |
POWER(x, y), POW(x, y) | x to the power y: x بە y: | POWER(2, 3) | 8 |
MOD(a, b), a % b | the remainder of () | MOD(21, 2) | 1 |
ABS(x) | the value without its minus signنرخەکە بەبێ نیشانەی کەم | ABS(-7500) | 7500 |
CEIL(x), FLOOR(x) | the next whole number up / down دواتر بەرەو سەرەوە / خوارەوە | CEIL(4.2), FLOOR(4.8) | 5, 4 |
SELECT ROUND(342.9234, -1), ROUND(2912.564, 1), ROUND(283.2),
POWER(2, 3), MOD(21, 2), 21 % 2;+---------------------+--------------------+--------------+-------------+------------+--------+ | ROUND(342.9234, -1) | ROUND(2912.564, 1) | ROUND(283.2) | POWER(2, 3) | MOD(21, 2) | 21 % 2 | +---------------------+--------------------+--------------+-------------+------------+--------+ | 340 | 2912.6 | 283 | 8 | 1 | 1 | +---------------------+--------------------+--------------+-------------+------------+--------+ 1 row in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
A negative number of places rounds to the left of the point: -1 to the nearest ten, -2 to the nearest hundred, -3 to the nearest thousand. For exact numbers MySQL rounds a half away from zero: ROUND(18750, -3) is 19000.
ئەگەر ژمارەی شوێنەکان سالب بێت، بۆ لای چەپی خاڵەکە خڕ دەکاتەوە: -1 بۆ نزیکترین دە، -2 بۆ نزیکترین سەد، -3 بۆ نزیکترین هەزار. بۆ ژمارە وردەکان MySQL نیوە بە دوور لە سفر خڕ دەکاتەوە: ROUND(18750, -3) دەبێتە 19000.
Numeric functionsکردارە ژمارەییەکان
Prices, instalments and UPDATEقیمەت، قیست و UPDATE
Shops in Kurdistan price in whole thousands of dinars. A 10 % price rise, rounded to the nearest thousand:
دوکانەکانی کوردستان بە هەزارانی تەواوی دینار قیمەت دادەنێن. بەرزکردنەوەی قیمەت بە 10 %، خڕکراوە بۆ نزیکترین هەزار:
SELECT name, price_iqd, ROUND(price_iqd * 1.1, -3) AS new_price
FROM products
WHERE category IN ('charger', 'headphones');+---------------------+-----------+-----------+ | name | price_iqd | new_price | +---------------------+-----------+-----------+ | USB-C Charger 25W | 25000 | 28000 | | Fast Charger 33W | 18000 | 20000 | | Power Bank 20000mAh | 30000 | 33000 | | Galaxy Buds FE | 95000 | 105000 | | Wired Earphones | 7500 | 8000 | +---------------------+-----------+-----------+ 5 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite ignores the −3 and shows 27500.0, 19800.0, 33000.0, 104500.0 and 8250.0.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite −3 پشتگوێ دەخات و 27500.0، 19800.0، 33000.0، 104500.0 و 8250.0 پیشان دەدات.
The same function can change stored data inside UPDATE. Try it on a copy first, so a mistake costs nothing:
هەمان دەتوانێت لە ناو UPDATE هەڵگیراو بگۆڕێت. سەرەتا لەسەر کۆپییەک تاقی بکەرەوە، بۆ ئەوەی هەڵەیەک هیچ زیانێکی نەبێت:
CREATE TABLE products_copy AS SELECT * FROM products; -- a copy to practise on
UPDATE products_copy
SET price_iqd = ROUND(price_iqd * 1.1, -3)
WHERE category = 'charger';
SELECT name, price_iqd FROM products_copy WHERE category = 'charger';Query OK, 3 rows affected +---------------------+-----------+ | name | price_iqd | +---------------------+-----------+ | USB-C Charger 25W | 28000 | | Fast Charger 33W | 20000 | | Power Bank 20000mAh | 33000 | +---------------------+-----------+ 3 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). In SQLite the copy holds 27500, 19800 and 33000, because its round() ignores −3.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). لە SQLite کۆپییەکە 27500، 19800 و 33000 هەڵدەگرێت، چونکە round()ـەکەی −3 پشتگوێ دەخات.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 3-5
Without the
WHEREevery product would get the new price (UPDATE without WHERE).بەبێ
WHEREهەموو کاڵایەک قیمەتە نوێیەکە وەردەگرێت (UPDATE بەبێ WHERE).
MOD and FLOOR split a price into ten monthly instalments in whole thousands, plus the rest paid at once. A monthly payment is the price divided by 10, cut down to whole thousands — FLOOR(price_iqd / 10000) * 1000 — and what is left is MOD(price_iqd, 10000):
MOD و FLOOR قیمەتێک دابەش دەکەن بۆ دە قیستی مانگانە بە هەزارانی تەواو، لەگەڵ ئەوەی دەمێنێتەوە و یەکجار دەدرێت. قیستی مانگانە قیمەتەکەیە دابەش بە 10، کورتکراوە بۆ هەزارانی تەواو — FLOOR(price_iqd / 10000) * 1000 — و ئەوەی دەمێنێتەوە MOD(price_iqd, 10000)ـە:
SELECT name, price_iqd,
FLOOR(price_iqd / 10000) * 1000 AS monthly,
MOD(price_iqd, 10000) AS pay_now
FROM products
WHERE category = 'phone';+---------------+-----------+---------+---------+ | name | price_iqd | monthly | pay_now | +---------------+-----------+---------+---------+ | Galaxy A15 | 250000 | 25000 | 0 | | Redmi 13C | 165000 | 16000 | 5000 | | Redmi Note 13 | 285000 | 28000 | 5000 | | iPhone 15 | 1350000 | 135000 | 0 | +---------------+-----------+---------+---------+ 4 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives the same numbers, with pay_now as 0.0 and 5000.0.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite هەمان ژمارەکان دەدات، بەڵام pay_now وەک 0.0 و 5000.0.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 2-3
Check the Redmi 13C: .
Redmi 13C بپشکنە: .
A seller's commission (2 % of what they sold, rounded to whole dinars) needs the prices of the sold products, so it is computed after GROUP BY and a join: see GROUP BY over a join.
کۆمیسیۆنی فرۆشیارێک (2 %ی ئەوەی فرۆشتوویەتی، خڕکراوە بۆ دیناری تەواو) پێویستی بە قیمەتی کاڵا فرۆشراوەکانە، بۆیە دوای GROUP BY و دەژمێردرێت: بڕوانە GROUP BY لەگەڵ لێکبەستن.
Text functionsکردارە دەقییەکان
Text functions change, measure and cut . Positions in SQL start at 1, not 0.
دەگۆڕن، دەپێون و دەبڕن. شوێن لە SQLـدا لە 1ـەوە دەست پێدەکات، نەک 0.
| Function | What it doesچی دەکات | Exampleنموونە | Answerوەڵام |
|---|---|---|---|
UPPER(s), UCASE(s) | capital lettersپیتی گەورە | UPPER('Hana') | HANA |
LOWER(s), LCASE(s) | small lettersپیتی بچووک | LOWER('Erbil') | erbil |
SUBSTRING(s, pos, n) | n characters from position pos (also SUBSTR, MID); without n, to the endn لە شوێنی posـەوە (هەروەها SUBSTR، MID)؛ بەبێ n تا کۆتایی | SUBSTRING('Redmi Note 13', 7, 4) | Note |
LEFT(s, n), RIGHT(s, n) | the first / last n charactersیەکەم / دوایین n | LEFT('Redmi Note 13', 5) | Redmi |
INSTR(s, part) | the position where part first appears; 0 if it is not thereئەو شوێنەی part یەکەم جار تێیدا دەردەکەوێت؛ 0 ئەگەر نەبێت | INSTR('Redmi Note 13', 'Note') | 7 |
TRIM(s), LTRIM(s), RTRIM(s) | remove spaces at both ends / the left / the rightبۆشایی لە هەردوو سەر / چەپ / ڕاست لادەبات | TRIM(' Erbil ') | Erbil |
LENGTH(s), CHAR_LENGTH(s) | the length in bytes / in charactersدرێژی بە / بە | CHAR_LENGTH('Hana') | 4 |
CONCAT(a, b, …) | joins texts end to end ()دەقەکان بە دوای یەکدا دەلکێنێت () | CONCAT('Aram', ' (', 'Sulaimani', ')') | Aram (Sulaimani) |
SELECT name, UPPER(name), LOWER(city)
FROM customers
WHERE customer_id <= 3;+--------+-------------+-------------+ | name | UPPER(name) | LOWER(city) | +--------+-------------+-------------+ | Aram | ARAM | sulaimani | | Shilan | SHILAN | erbil | | Karwan | KARWAN | duhok | +--------+-------------+-------------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT SUBSTRING('Redmi Note 13', 7, 4), MID('Redmi Note 13', 7),
LEFT('Redmi Note 13', 5), RIGHT('Redmi Note 13', 2);+----------------------------------+-------------------------+--------------------------+---------------------------+
| SUBSTRING('Redmi Note 13', 7, 4) | MID('Redmi Note 13', 7) | LEFT('Redmi Note 13', 5) | RIGHT('Redmi Note 13', 2) |
+----------------------------------+-------------------------+--------------------------+---------------------------+
| Note | Note 13 | Redmi | 13 |
+----------------------------------+-------------------------+--------------------------+---------------------------+
1 row in setMySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite has no MID, LEFT or RIGHT (its SUBSTRING is the same as substr()): substr('Redmi Note 13', 1, 5) and substr('Redmi Note 13', -2) give the same Redmi and 13.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite هیچ MID، LEFT یان RIGHTـی نییە (SUBSTRINGـەکەی هەمان substr()ـە): substr('Redmi Note 13', 1, 5) و substr('Redmi Note 13', -2) هەمان Redmi و 13 دەدەن.
SELECT INSTR('Redmi Note 13', 'Note'), INSTR('Redmi Note 13', 'Pro');+--------------------------------+-------------------------------+
| INSTR('Redmi Note 13', 'Note') | INSTR('Redmi Note 13', 'Pro') |
+--------------------------------+-------------------------------+
| 7 | 0 |
+--------------------------------+-------------------------------+
1 row in setRun in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
0 means not found. In MySQL
INSTRignores letter case with the default collation; in SQLite it does not (INSTR('Redmi Note 13', 'note')is 0 there).0 واتە نەدۆزرایەوە. لە MySQL
INSTRبە بنەڕەتی گەورە و بچووکیی پیت پشتگوێ دەخات؛ لە SQLite نا (INSTR('Redmi Note 13', 'note')لەوێ 0ـە).
SELECT LENGTH(' Erbil '), LENGTH(TRIM(' Erbil ')),
LENGTH(LTRIM(' Erbil ')), LENGTH(RTRIM(' Erbil '));+--------------------+--------------------------+---------------------------+---------------------------+
| LENGTH(' Erbil ') | LENGTH(TRIM(' Erbil ')) | LENGTH(LTRIM(' Erbil ')) | LENGTH(RTRIM(' Erbil ')) |
+--------------------+--------------------------+---------------------------+---------------------------+
| 8 | 5 | 6 | 7 |
+--------------------+--------------------------+---------------------------+---------------------------+
1 row in setRun in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1-2
Two spaces in front and one behind: 8 characters, 5 after
TRIM, 6 afterLTRIM, 7 afterRTRIM.دوو بۆشایی لە پێشەوە و یەک لە دواوە: 8 ، 5 دوای
TRIM، 6 دوایLTRIM، 7 دوایRTRIM.
CONCAT builds new text from columns. Careful with NULL: in MySQL one NULL argument makes the whole result NULL.
CONCAT لە دەقی نوێ دروست دەکات. ئاگاداری NULL بە: لە MySQL یەک NULL هەموو ئەنجامەکە دەکاتە NULL.
SELECT name,
CONCAT(name, ' (', city, ')') AS label,
CONCAT(name, ' <', email, '>') AS contact
FROM customers
WHERE customer_id IN (1, 6);+-------+------------------+-------------------------+ | name | label | contact | +-------+------------------+-------------------------+ | Aram | Aram (Sulaimani) | Aram <aram@example.com> | | Soran | Soran (Kirkuk) | NULL | +-------+------------------+-------------------------+ 2 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite's concat() skips NULL arguments and gives 'Soran <>'; its || operator gives NULL like MySQL.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). concat()ـی SQLite NULL پشتگوێ دەخات و 'Soran <>' دەدات؛ ||ـەکەی وەک MySQL NULL دەدات.
MySQL text functions one by one: LENGTH, UPPER and LOWER, TRIM, LEFT and RIGHT, SUBSTRING, REPLACE, LOCATE and CONCAT.
یەک بە یەک: LENGTH، UPPER و LOWER، TRIM، LEFT و RIGHT، SUBSTRING، REPLACE، LOCATE و CONCAT.
Whole video, MySQL Workbench: LENGTH 0:20, UPPER/LOWER 1:48, TRIM 3:01, LEFT/RIGHT 4:22, SUBSTRING 6:25, REPLACE 8:14, LOCATE 9:10, CONCAT 10:18. For Kurdish text use CHAR_LENGTH (next screen).
هەموو ڤیدیۆکە، لە Workbench: LENGTH لە 0:20، UPPER/LOWER لە 1:48، TRIM لە 3:01، LEFT/RIGHT لە 4:22، SUBSTRING لە 6:25، REPLACE لە 8:14، LOCATE لە 9:10 و CONCAT لە 10:18. بۆ دەقی کوردی CHAR_LENGTH بەکاربهێنە (بەشی داهاتوو).
Text functionsکردارە دەقییەکان
LENGTH or CHAR_LENGTH? Kurdish textLENGTH یان CHAR_LENGTH؟ دەقی کوردی
The textbook says LENGTH returns the number of characters. That is only true for English letters. MySQL stores text as UTF-8 (), where an English letter takes one byte but a Kurdish (Arabic-script) letter takes two (UTF-8: one to four bytes). LENGTH counts bytes; CHAR_LENGTH counts characters:
کتێبەکە دەڵێت LENGTH ژمارەی دەگەڕێنێتەوە. ئەمە تەنها بۆ پیتی ئینگلیزی ڕاستە. MySQL دەق بە UTF-8 () هەڵدەگرێت کە تێیدا پیتێکی ئینگلیزی یەک دەگرێت، بەڵام پیتێکی کوردی (بە ئەلفوبێی عەرەبی) دوو (UTF-8: یەک تا چوار بایت). LENGTH دەژمێرێت؛ CHAR_LENGTH :
SELECT LENGTH('Shilan'), CHAR_LENGTH('Shilan'),
LENGTH('شیلان'), CHAR_LENGTH('شیلان');+------------------+-----------------------+-----------------+----------------------+
| LENGTH('Shilan') | CHAR_LENGTH('Shilan') | LENGTH('شیلان') | CHAR_LENGTH('شیلان') |
+------------------+-----------------------+-----------------+----------------------+
| 6 | 6 | 10 | 5 |
+------------------+-----------------------+-----------------+----------------------+
1 row in setMySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
شیلان has five letters, and each is stored in two bytes, so LENGTH says 10. Use CHAR_LENGTH whenever you mean how many letters — for example to check that a name is not longer than its VARCHAR(40) column, because VARCHAR(n) also counts characters.
شیلان پێنج پیتە و هەر پیتێک لە دوو هەڵدەگیرێت، بۆیە LENGTH دەڵێت 10. هەر کاتێک مەبەستت چەند پیتـە CHAR_LENGTH بەکار بهێنە — بۆ نموونە بۆ پشکنینی ئەوەی ناوێک لە VARCHAR(40)ـەکەی درێژتر نییە، چونکە VARCHAR(n)ـیش دەژمێرێت.
Text functionsکردارە دەقییەکان
Splitting an e-mail addressلەتکردنی ناونیشانێکی ئیمەیڵ
INSTR finds where the @ is; LEFT and SUBSTRING cut before and after it. The user name is everything before the @ (position − 1 characters); the domain starts one position after it:
INSTR شوێنی @ دەدۆزێتەوە؛ LEFT و SUBSTRING پێش و دوای ئەو دەبڕن. هەموو ئەوەیە کە پێش @ دێت (شوێن − 1 )؛ دۆمەین یەک شوێن دوای ئەو دەست پێدەکات:
SELECT email,
LEFT(email, INSTR(email, '@') - 1) AS user_name,
SUBSTRING(email, INSTR(email, '@') + 1) AS domain
FROM customers;+----------------------+-----------+-------------+ | email | user_name | domain | +----------------------+-----------+-------------+ | aram@example.com | aram | example.com | | shilan.k@example.com | shilan.k | example.com | | karwan88@example.com | karwan88 | example.com | | dilan@example.com | dilan | example.com | | hana.m@example.com | hana.m | example.com | | NULL | NULL | NULL | +----------------------+-----------+-------------+ 6 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives the same rows with substr(email, 1, INSTR(email, '@') - 1) and substr(email, INSTR(email, '@') + 1).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite هەمان بە substr(email, 1, INSTR(email, '@') - 1) و substr(email, INSTR(email, '@') + 1) دەدات.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 6
Soran has no e-mail: every function of
NULLgivesNULL.Soran نییە: هەر کە
NULLوەربگرێتNULLدەدات.
TRIM can also remove a given text from one end. The textbook removes .com from e-mails; in MySQL that is TRIM(TRAILING '.com' FROM email):
TRIM دەتوانێت دەقێکی دیاریکراویش لە سەرێک لابەرێت. کتێبەکە .com لە ئیمەیڵەکان لادەبات؛ لە MySQL ئەوە TRIM(TRAILING '.com' FROM email)ـە:
SELECT email, TRIM(TRAILING '.com' FROM email) AS without_com
FROM customers
WHERE customer_id <= 3;+----------------------+------------------+ | email | without_com | +----------------------+------------------+ | aram@example.com | aram@example | | shilan.k@example.com | shilan.k@example | | karwan88@example.com | karwan88@example | +----------------------+------------------+ 3 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite has no TRIM(… FROM …): its trim(x, y) removes any of the characters in y, so trim('com.example.com', '.com') gives example.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite TRIM(… FROM …)ـی نییە: trim(x, y)ـەکەی هەر یەکێک لە ناو y لادەبات، بۆیە trim('com.example.com', '.com') example دەدات.
Text functions also work in WHERE. The textbook's two activities, on our shop: brands that start with S in capitals, and the first ten characters of every long product name.
لە WHEREـیش کار دەکەن. دوو چالاکییەکەی کتێبەکە، لەسەر دوکانەکەمان: ئەو براندانەی بە S دەست پێدەکەن بە پیتی گەورە و یەکەم دە هەموو ناوێکی درێژی کاڵا.
SELECT UPPER(brand) AS brand, name FROM products WHERE brand LIKE 'S%';+---------+-------------------+ | brand | name | +---------+-------------------+ | SAMSUNG | Galaxy A15 | | SAMSUNG | USB-C Charger 25W | | SAMSUNG | Galaxy Buds FE | +---------+-------------------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT name, SUBSTRING(name, 1, 10) AS short_name
FROM products
WHERE CHAR_LENGTH(name) > 15;+---------------------+------------+ | name | short_name | +---------------------+------------+ | USB-C Charger 25W | USB-C Char | | Fast Charger 33W | Fast Charg | | Power Bank 20000mAh | Power Bank | +---------------------+------------+ 3 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
Date functionsکردارەکانی بەروار
Date functions read the clock or take a date apart. They return numbers (the year 2026), text (October) or a new date.
بەروار کاتژمێر دەخوێننەوە یان بەروارێک دەکەنە بەش. ژمارە (ساڵی 2026)، دەق (October) یان بەرواری نوێ دەگەڕێننەوە.
| Function | Givesدەدات | Exampleنموونە | MySQL answerوەڵامی MySQL |
|---|---|---|---|
NOW() | the date and time now (server clock)بەروار و کاتی ئێستا (کاتژمێری ) | NOW() | e.g. 2026-10-25 and the timeبۆ نموونە 2026-10-25 و کاتەکە |
CURDATE() | today's dateبەرواری ئەمڕۆ | CURDATE() | 2026-10-25 (on that day)2026-10-25 (لەو ڕۆژەدا) |
DATE(x) | the date part of a date and timeبەشی بەرواری بەروار و کاتێک | DATE('2026-10-24 18:05:00') | 2026-10-24 |
YEAR(d), MONTH(d), DAY(d) | the year, month and day as numbersساڵ، مانگ و ڕۆژ وەک ژمارە | MONTH('2026-10-09') | 10 |
MONTHNAME(d) | the name of the monthناوی مانگەکە | MONTHNAME('2026-10-09') | October |
DAYNAME(d) | the name of the weekdayناوی ڕۆژی هەفتە | DAYNAME('2026-10-09') | Friday |
DAYOFWEEK(d) | weekday as a number: 1 = Sunday … 7 = Saturdayڕۆژی هەفتە وەک ژمارە: 1 = یەکشەممە … 7 = شەممە | DAYOFWEEK('2026-10-09') | 6 |
DATE_FORMAT(d, f) | the date as text in a patternبەروارەکە وەک دەق بە شێوەیەکی دیاریکراو | DATE_FORMAT('2026-10-09', '%W, %e %M %Y') | Friday, 9 October 2026 |
DATEDIFF(a, b) | the number of days from b to aژمارەی ڕۆژەکان لە bـەوە تا a | DATEDIFF('2026-10-25', '2026-09-02') | 53 |
The day, month and year of three sales (the textbook asks the same about the day each employee joined):
ڕۆژ، مانگ و ساڵی سێ فرۆشتن (کتێبەکە هەمان پرسیار دەربارەی ئەو ڕۆژە دەکات کە هەر فەرمانبەرێک دەستی بە کار کردووە):
SELECT sold_on, YEAR(sold_on), MONTH(sold_on), DAY(sold_on),
MONTHNAME(sold_on), DAYNAME(sold_on)
FROM sales
WHERE sale_id IN (1, 13, 20);+------------+---------------+----------------+--------------+--------------------+------------------+ | sold_on | YEAR(sold_on) | MONTH(sold_on) | DAY(sold_on) | MONTHNAME(sold_on) | DAYNAME(sold_on) | +------------+---------------+----------------+--------------+--------------------+------------------+ | 2026-09-02 | 2026 | 9 | 2 | September | Wednesday | | 2026-10-09 | 2026 | 10 | 9 | October | Friday | | 2026-10-24 | 2026 | 10 | 24 | October | Saturday | +------------+---------------+----------------+--------------+--------------------+------------------+ 3 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
Date functionsکردارەکانی بەروار
The weekend: DAYNAME in WHEREپشووی کۆتایی هەفتە: DAYNAME لە WHERE
A single-row function can be used inside WHERE. In Kurdistan, Friday is the main day off of the week, so the owner wants to know which sales happened on a Friday:
دەتوانرێت لە ناو WHERE بەکار بهێنرێت. لە کوردستان هەینی ڕۆژی سەرەکیی پشووی هەفتەیە، بۆیە خاوەنی دوکانەکە دەیەوێت بزانێت کام فرۆشتن لە ڕۆژی هەینیدا بووە:
SELECT sale_id, sold_on, DAYNAME(sold_on) AS day
FROM sales
WHERE DAYNAME(sold_on) = 'Friday';+---------+------------+--------+ | sale_id | sold_on | day | +---------+------------+--------+ | 7 | 2026-09-18 | Friday | | 13 | 2026-10-09 | Friday | | 19 | 2026-10-23 | Friday | +---------+------------+--------+ 3 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives the same three sales with WHERE strftime('%w', sold_on) = '5'.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite بە WHERE strftime('%w', sold_on) = '5' هەمان سێ فرۆشتن دەدات.
The other way round — every sale not on a Friday — is <>; 17 of the 20 sales. The textbook also shows such dates in a long form such as Wednesday, 2 September 2026; DATE_FORMAT does it in one step:
پێچەوانەکەی — هەموو فرۆشتنێک کە لە هەینیدا نەبووە — <>ـە؛ 17 لە 20 فرۆشتنەکە. کتێبەکە ئەم جۆرە بەروارانە بە شێوەیەکی درێژیش پیشان دەدات، وەک Wednesday, 2 September 2026؛ DATE_FORMAT بە یەک هەنگاو ئەمە دەکات:
SELECT COUNT(*) AS not_on_friday FROM sales WHERE DAYNAME(sold_on) <> 'Friday';+---------------+ | not_on_friday | +---------------+ | 17 | +---------------+ 1 row in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
SELECT sale_id, DATE_FORMAT(sold_on, '%W, %e %M %Y') AS nice_date
FROM sales
WHERE sale_id IN (1, 13);+---------+-----------------------------+ | sale_id | nice_date | +---------+-----------------------------+ | 1 | Wednesday, 2 September 2026 | | 13 | Friday, 9 October 2026 | +---------+-----------------------------+ 2 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
%Wweekday name,%eday without a leading zero,%Mmonth name,%Yfour-digit year.%Wناوی ڕۆژی هەفتە،%eڕۆژ بەبێ سفری پێشەوە،%Mناوی مانگ،%Yساڵی چوار ژمارەیی.
Aggregate functions: one answer from many rowsکردارەکانی کۆکردنەوە: یەک وەڵام لە چەندین تۆمار
Five answer the questions every shop owner asks: how many, how much in total, on average, the least, the most. Without GROUP BY they treat all the rows that pass WHERE as one group.
پێنج وەڵامی ئەو پرسیارانە دەدەنەوە کە هەموو خاوەن دوکانێک دەیانکات: چەند، کۆی گشتی چەند، بە تێکڕا، کەمترین، زۆرترین. بەبێ GROUP BY هەموو ئەو لە WHERE تێدەپەڕن وەک یەک گرووپ دادەنێن.
| Function | Givesدەدات | NULL valuesنرخەکانی NULL |
|---|---|---|
COUNT(*) | the number of rowsژمارەی | counted — it counts rows, not valuesدەژمێردرێن — دەژمێرێت، نەک نرخ |
COUNT(column) | the number of values in the columnژمارەی نرخەکانی ناو | skippedپشتگوێ دەخرێن |
COUNT(DISTINCT column) | the number of different valuesژمارەی نرخە جیاوازەکان | skippedپشتگوێ دەخرێن |
SUM(column) | the total (numbers only)کۆی گشتی (تەنها ژمارە) | skippedپشتگوێ دەخرێن |
AVG(column) | the average, the arithmetic (numbers only)تێکڕا، واتە ژمێرەیی (تەنها ژمارە) | skipped — not counted as 0پشتگوێ دەخرێن — وەک 0 هەژمار ناکرێن |
MIN(column), MAX(column) | the smallest / largest — numbers, text or datesبچووکترین / گەورەترین — ژمارە، دەق یان بەروار | skippedپشتگوێ دەخرێن |
SELECT COUNT(*), COUNT(email), COUNT(DISTINCT city) FROM customers;+----------+--------------+----------------------+ | COUNT(*) | COUNT(email) | COUNT(DISTINCT city) | +----------+--------------+----------------------+ | 6 | 5 | 5 | +----------+--------------+----------------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
6 customers; 5 e-mail addresses, because Soran's is
NULL; 5 cities, because Aram and Dilan both live in Sulaimani.6 کڕیار؛ 5 ، چونکە هی Soran
NULLـە؛ 5 شار، چونکە Aram و Dilan هەردووکیان لە سلێمانی دەژین.
The total, the average, the cheapest and the dearest of the four phones:
کۆ، تێکڕا، هەرزانترین و گرانترینی چوار مۆبایلەکە:
SELECT SUM(price_iqd), AVG(price_iqd), MIN(price_iqd), MAX(price_iqd)
FROM products
WHERE category = 'phone';+----------------+----------------+----------------+----------------+ | SUM(price_iqd) | AVG(price_iqd) | MIN(price_iqd) | MAX(price_iqd) | +----------------+----------------+----------------+----------------+ | 2050000 | 512500.0000 | 165000 | 1350000 | +----------------+----------------+----------------+----------------+ 1 row in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives the same numbers, but AVG as 512500.0.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite هەمان ژمارەکان دەدات، بەڵام AVG وەک 512500.0.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
MySQL returns
AVG(andSUM) of whole numbers as an exactDECIMAL; the average shows four decimal places. SQLite returns a decimal fraction (a float).MySQL
AVG(وSUM)ی وەکDECIMALـێکی ورد دەگەڕێنێتەوە؛ تێکڕاکە چوار شوێنی دوای خاڵ پیشان دەدات. SQLite دەگەڕێنێتەوە.
In Kurdish: how to add, read, filter, change and delete rows with INSERT, SELECT, WHERE, UPDATE and DELETE.
بە کوردی فێر دەبیت چۆن زیاد دەکەیت، دەخوێنیتەوە، دەکەیت، دەگۆڕیت و دەسڕیتەوە بە ، ، ، و .
Kurdish (Sorani). Plays 18:55-20:45 (Aggregate Functions): a slide of the five functions in Kurdish, then COUNT and GROUP BY; frames checked.
بە کوردیی سۆرانی، لە 18:55 تا 20:45 پەخش دەبێت (بەشی Aggregate Functions): بە کوردی دەربارەی پێنج ، پاشان COUNT و .
Aggregate functions: one answer from many rowsکردارەکانی کۆکردنەوە: یەک وەڵام لە چەندین تۆمار
AVG and NULL, and naming an aggregateAVG و NULL و ناونانی کردارێکی کۆکردنەوە
AVG is the arithmetic mean you know from statistics (the mean of ungrouped data). It divides by the number of values, not rows. The laptops have stocks 4, NULL and 5:
AVG هەمان ژمێرەییە کە لە ئامارەوە دەیناسیت (ناوەندی داتای گرووپنەکراو). دابەشی ژمارەی نرخەکان دەکات، نەک . کۆگایان 4، NULL و 5ـە:
SELECT SUM(stock), AVG(stock), COUNT(stock), COUNT(*)
FROM products
WHERE category = 'laptop';+------------+------------+--------------+----------+ | SUM(stock) | AVG(stock) | COUNT(stock) | COUNT(*) | +------------+------------+--------------+----------+ | 9 | 4.5000 | 2 | 3 | +------------+------------+--------------+----------+ 1 row in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite: 9 | 4.5 | 2 | 3.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite: 9 | 4.5 | 2 | 3.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
. If the unknown stock were counted as 0, the average would be — a different answer.
. ئەگەر کۆگا نەزانراوەکە وەک 0 هەژمار بکرایە، تێکڕاکە دەبووە — وەڵامێکی جیاواز.
An aggregate can be combined with WHERE, and its column can get an alias. How many Samsung products are there, and what do they cost at least and at most?
دەتوانرێت لەگەڵ WHERE تێکەڵ بکرێت و وەربگرێت. چەند کاڵای Samsung هەیە و کەمترین و زۆرترین قیمەتیان چەندە؟
SELECT COUNT(*) AS samsung_products, MIN(price_iqd), MAX(price_iqd)
FROM products
WHERE brand = 'Samsung';+------------------+----------------+----------------+ | samsung_products | MIN(price_iqd) | MAX(price_iqd) | +------------------+----------------+----------------+ | 3 | 25000 | 250000 | +------------------+----------------+----------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Aggregate functions: one answer from many rowsکردارەکانی کۆکردنەوە: یەک وەڵام لە چەندین تۆمار
MIN and MAX on text and datesMIN و MAX لەسەر دەق و بەروار
MIN and MAX compare any values that can be put in order: numbers by size, text alphabetically (by the ), dates by time. The first and last product name, and the oldest and newest product:
MIN و MAX هەر نرخێک بەراورد دەکەن کە بتوانرێت ڕیز بکرێت: ژمارە بەپێی قەبارە، دەق بەپێی ئەلفوبێ (بەپێی )، بەروار بەپێی کات. یەکەم و دوایین ناوی کاڵا و کۆنترین و نوێترین کاڵا:
SELECT MIN(name), MAX(name), MIN(added_on), MAX(added_on) FROM products;+------------------+-----------------+---------------+---------------+ | MIN(name) | MAX(name) | MIN(added_on) | MAX(added_on) | +------------------+-----------------+---------------+---------------+ | Fast Charger 33W | Wired Earphones | 2026-01-10 | 2026-08-30 | +------------------+-----------------+---------------+---------------+ 1 row in set
MySQL's answer (checked in SQLite with a case-insensitive collation). Plain SQLite says MAX(name) is iPhone 15, because there a small i comes after every capital letter.
وەڵامی MySQL (لە SQLite بە پشکنراوە کە گەورە و بچووکیی پیت جیا ناکاتەوە). SQLiteـی ئاسایی دەڵێت MAX(name) iPhone 15ـە، چونکە لەوێ iـی بچووک دوای هەموو پیتێکی گەورە دێت.
The same works on the sales: SELECT MIN(sold_on), MAX(sold_on) FROM sales; gives the first and the last day of sales, 2026-09-02 and 2026-10-24.
هەمان شت لەسەر فرۆشتنەکان کار دەکات: SELECT MIN(sold_on), MAX(sold_on) FROM sales; یەکەم و دوایین ڕۆژی فرۆشتن دەدات، 2026-09-02 و 2026-10-24.
Aggregate functions: one answer from many rowsکردارەکانی کۆکردنەوە: یەک وەڵام لە چەندین تۆمار
DISTINCT inside aggregates, and an empty resultDISTINCT لە ناو کردارەکانی کۆکردنەوەدا و ئەنجامی بەتاڵ
DISTINCT inside the brackets counts or adds every different value once. The 20 sales sold 27 items; the different quantities are 1, 2 and 3:
DISTINCT لە ناو کەوانەکاندا هەر نرخێکی جیاواز یەک جار دەژمێرێت یان کۆ دەکاتەوە. 20 فرۆشتنەکە 27 دانەیان فرۆشتووە؛ بڕە جیاوازەکان 1، 2 و 3ـن:
SELECT SUM(quantity), SUM(DISTINCT quantity), COUNT(DISTINCT quantity)
FROM sales;+---------------+------------------------+--------------------------+ | SUM(quantity) | SUM(DISTINCT quantity) | COUNT(DISTINCT quantity) | +---------------+------------------------+--------------------------+ | 27 | 6 | 3 | +---------------+------------------------+--------------------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
What happens when WHERE matches no row? Nobody paid by cheque:
چی ڕوودەدات کاتێک WHERE هیچ نادۆزێتەوە؟ کەس بە چەک پارەی نەداوە:
SELECT COUNT(*), SUM(quantity), AVG(quantity), MAX(sold_on)
FROM sales
WHERE payment = 'cheque';+----------+---------------+---------------+--------------+ | COUNT(*) | SUM(quantity) | AVG(quantity) | MAX(sold_on) | +----------+---------------+---------------+--------------+ | 0 | NULL | NULL | NULL | +----------+---------------+---------------+--------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
COUNTof nothing is 0;SUM,AVG,MINandMAXof nothing are NULL (there is no total, average or largest of nothing).COUNTـی هیچ 0ـە؛SUM،AVG،MINوMAXـی هیچ NULLـن (هیچ کۆ، تێکڕا یان گەورەترینێک بۆ هیچ نییە).
In a report you usually want 0, not NULL. COALESCE gives it:
لە ڕاپۆرتدا زۆرجار 0ت دەوێت، نەک NULL. COALESCE ئەوە دەدات:
SELECT COALESCE(SUM(quantity), 0) AS items FROM sales WHERE payment = 'cheque';+-------+ | items | +-------+ | 0 | +-------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
An aggregate next to a plain columnکردارێکی کۆکردنەوە لە تەنیشت ستوونێکی ئاسایی
What is the most expensive product, and what is it called? A natural first try mixes a plain column with an aggregate:
گرانترین کاڵا کامەیە و ناوی چییە؟ یەکەم هەوڵی سروشتی ئاسایی لەگەڵ تێکەڵ دەکات:
SELECT name, MAX(price_iqd) FROM products;MAX folds 12 rows into one value, but name still has 12 values. Which one should the single answer row show? Standard SQL says: with an aggregate and no GROUP BY, every other column must be inside an aggregate too. The three databases you may meet react differently:
MAX 12 دەپێچێتەوە بۆ یەک نرخ، بەڵام name هێشتا 12 نرخی هەیە. یەک وەڵامەکە کامیان پیشان بدات؟ SQLـی ستاندارد دەڵێت: لەگەڵ و بەبێ GROUP BY، هەموو تر دەبێت ئەویش لە ناو بێت. ئەو سێ لەوانەیە بیانبینیت بە شێوەی جیاواز وەڵام دەدەنەوە:
| Database | What happensچی ڕوودەدات |
|---|---|
| MySQL 8.4 | Refused, because the SQL mode ONLY_FULL_GROUP_BY is on by default: ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'shop.products.name'; this is incompatible with sql_mode=only_full_group_byڕەت دەکرێتەوە، چونکە دۆخی SQLـی ONLY_FULL_GROUP_BY بە شێوەی بنەڕەتی چالاکە: ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'shop.products.name'; this is incompatible with sql_mode=only_full_group_by |
| MariaDB (XAMPP)MariaDB (لە XAMPP) | Accepted: ONLY_FULL_GROUP_BY is off by default. The name comes from an arbitrary row — not necessarily the iPhone. The answer looks right but may be wrong.وەردەگیرێت: ONLY_FULL_GROUP_BY بە شێوەی بنەڕەتی ناچالاکە. ناوەکە لە هەڕەمەکیـەوە دێت — نەک بە دڵنیاییەوە iPhone. وەڵامەکە ڕاست دەردەکەوێت بەڵام لەوانەیە هەڵە بێت. |
| SQLite | Accepted, with a special rule: when the query has exactly one MIN() or MAX(), the other columns come from the row that holds it. The answer below is SQLite's.وەردەگیرێت، بە یاسایەکی تایبەت: کاتێک ڕێک یەک MIN() یان MAX()ـی هەیە، تر لەو دێن کە ئەو نرخەی تێدایە. وەڵامی خوارەوە هی SQLiteـە. |
SELECT name, MAX(price_iqd) FROM products; -- SQLite only+-----------+----------------+ | name | MAX(price_iqd) | +-----------+----------------+ | iPhone 15 | 1350000 | +-----------+----------------+ 1 row in set
Run in SQLite 3.51 — this is SQLite's own answer.
لە SQLite 3.51 جێبەجێ کرا — ئەمە وەڵامی خودی SQLiteـە.
An aggregate next to a plain columnکردارێکی کۆکردنەوە لە تەنیشت ستوونێکی ئاسایی
The portable answer: a subqueryوەڵامی گشتگیر: ژێرپرسێک
Do not depend on any of these. The portable answer asks two questions, one inside the other: first what is the highest price?, then which product has that price?. The inner SELECT in brackets is a :
پشت بە هیچیان مەبەستە. وەڵامی گشتگیر دوو پرسیار دەکات، یەکێکیان لە ناو ئەوی تردا: یەکەم بەرزترین قیمەت چەندە؟، پاشان کام کاڵا ئەو قیمەتەی هەیە؟. SELECTـی ناوەوە لە ناو کەوانەدا :
SELECT name, price_iqd
FROM products
WHERE price_iqd = (SELECT MAX(price_iqd) FROM products);+-----------+-----------+ | name | price_iqd | +-----------+-----------+ | iPhone 15 | 1350000 | +-----------+-----------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 3
The subquery runs first and gives 1350000; the outer query then finds every product with that price — all of them if two products share the top price.
یەکەم جێبەجێ دەکرێت و 1350000 دەدات؛ پاشان دەرەوە هەموو کاڵایەک بەو قیمەتە دەدۆزێتەوە — هەموویان ئەگەر دوو کاڵا هەمان بەرزترین قیمەتیان هەبێت.
GROUP BY: one answer per groupGROUP BY: یەک وەڵام بۆ هەر گرووپێک
How many products are there in each category? Without grouping you would need one query per category — WHERE category = 'phone', then 'laptop', and so on — and you would first have to know every category. does it in one query:
لە هەر جۆرێکدا چەند کاڵا هەیە؟ بەبێ گرووپکردن بۆ هەر جۆرێک پێویست دەبوو — WHERE category = 'phone'، پاشان 'laptop' و هتد — و دەبوو سەرەتا هەموو جۆرەکان بزانیت. بە یەک ئەمە دەکات:
SELECT category, COUNT(*) AS products,
MIN(price_iqd) AS cheapest, MAX(price_iqd) AS dearest
FROM products
GROUP BY category
ORDER BY category;+------------+----------+----------+---------+ | category | products | cheapest | dearest | +------------+----------+----------+---------+ | charger | 3 | 18000 | 30000 | | headphones | 2 | 7500 | 95000 | | laptop | 3 | 600000 | 940000 | | phone | 4 | 165000 | 1350000 | +------------+----------+----------+---------+ 4 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SQL puts the rows with the same category into one group and runs every aggregate once per group: one answer row for each of the four categories.
SQL ئەو هەمان categoryـیان هەیە دەخاتە یەک گرووپ و هەموو بۆ هەر گرووپێک یەک جار جێبەجێ دەکات: یەک وەڵام بۆ هەر یەک لە چوار جۆرەکە.
At the end of the day the shop's receipts are sorted into three piles: cash, card and FIB. Then each pile is counted and its amounts added up. GROUP BY payment makes the piles; COUNT and SUM work on each pile.
لە کۆتایی ڕۆژدا پسوولەکانی دوکانەکە دەکرێنە سێ کۆمەڵ: نەختینە، کارت و FIB. پاشان هەر کۆمەڵێک دەژمێردرێت و پارەکەی کۆ دەکرێتەوە. GROUP BY payment کۆمەڵەکان دروست دەکات؛ COUNT و SUM لەسەر هەر کۆمەڵێک کار دەکەن.
Where the analogy stops workingسنووری ئەم نموونەیە
A person sorting receipts can glance at a pile and say these are mostly phones. SQL can only report what you ask for with an aggregate or with a column you grouped by.
کەسێک کە پسوولە ڕیز دەکات دەتوانێت سەیری کۆمەڵێک بکات و بڵێت زۆربەی ئەمانە مۆبایلن. SQL تەنها ئەوە ڕاپۆرت دەکات کە بە یان بە کە گرووپی پێ کردووە داوای دەکەیت.
The sales of each seller, and the number of sales of each payment type — the textbook's cars sold by each employee and payments per payment mode, on our shop:
فرۆشتنەکانی هەر فرۆشیارێک و ژمارەی فرۆشتنی هەر جۆرێکی پارەدان — ئۆتۆمبێلی فرۆشراو لەلایەن هەر فەرمانبەرێکەوە و پارەدان بەپێی جۆری پارەدانـی کتێبەکە، لەسەر دوکانەکەمان:
SELECT seller, COUNT(*) AS sales, SUM(quantity) AS items
FROM sales
GROUP BY seller
ORDER BY seller;+--------+-------+-------+ | seller | sales | items | +--------+-------+-------+ | Lana | 9 | 12 | | Rezan | 11 | 15 | +--------+-------+-------+ 2 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT payment, COUNT(*) AS sales
FROM sales
GROUP BY payment
ORDER BY payment;+---------+-------+ | payment | sales | +---------+-------+ | card | 2 | | cash | 10 | | fib | 8 | +---------+-------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
GROUP BY: one answer per groupGROUP BY: یەک وەڵام بۆ هەر گرووپێک
The GROUP BY rule, and NULL as a groupیاسای GROUP BY و NULL وەک گرووپێک
NULLs form a group of their own: the power bank with no brand gets its own row (MySQL's manual: two NULL values are regarded as equal in a GROUP BY).
NULLـەکان گرووپێکی تایبەت بە خۆیان پێکدەهێنن: پاوەر بانکە بێ براندەکە تایبەت بە خۆی وەردەگرێت (ڕێبەری MySQL: دوو نرخی NULL لە GROUP BYـدا وەک یەکسان هەژمار دەکرێن).
SELECT brand, COUNT(*) AS products
FROM products
GROUP BY brand
ORDER BY brand;+---------+----------+ | brand | products | +---------+----------+ | NULL | 1 | | Apple | 1 | | Asus | 1 | | Lenovo | 2 | | Samsung | 3 | | Xiaomi | 4 | +---------+----------+ 6 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
GROUP BY: one answer per groupGROUP BY: یەک وەڵام بۆ هەر گرووپێک
Grouping by monthگرووپکردن بەپێی مانگ
You can group by an expression, such as the month of a date. Sales and items per month:
دەتوانیت بەپێی گرووپ بکەیت، وەک مانگی بەروارێک. فرۆشتن و دانەکان بۆ هەر مانگێک:
SELECT YEAR(sold_on) AS year, MONTHNAME(sold_on) AS month,
COUNT(*) AS sales, SUM(quantity) AS items
FROM sales
GROUP BY YEAR(sold_on), MONTH(sold_on), MONTHNAME(sold_on)
ORDER BY YEAR(sold_on), MONTH(sold_on);+------+-----------+-------+-------+ | year | month | sales | items | +------+-----------+-------+-------+ | 2026 | September | 9 | 13 | | 2026 | October | 11 | 14 | +------+-----------+-------+-------+ 2 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives the same 9 | 13 and 11 | 14 with GROUP BY strftime('%Y', sold_on), strftime('%m', sold_on).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite بە GROUP BY strftime('%Y', sold_on), strftime('%m', sold_on) هەمان 9 | 13 و 11 | 14 دەدات.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 4
MONTH()keeps the months in calendar order;MONTHNAME()is grouped too, because it appears inSELECT. The year is part of the group, so October 2026 and October 2027 would stay apart.MONTH()مانگەکان بە ڕیزبەندیی ساڵنامە دەهێڵێتەوە؛MONTHNAME()ـیش گرووپ دەکرێت چونکە لەSELECTـدا دەردەکەوێت. ساڵەکە بەشێکە لە گرووپەکە، بۆیە تشرینی یەکەمی 2026 و تشرینی یەکەمی 2027 لە یەک جیا دەمێننەوە.
GROUP BY: one answer per groupGROUP BY: یەک وەڵام بۆ هەر گرووپێک
GROUP BY over a joinGROUP BY لەسەر لێکبەستنێک
Brands and prices are in products, quantities in sales. An INNER JOIN puts each sale next to its product (joins); then GROUP BY works on the joined rows. AS s and AS p are short for the tables:
براند و قیمەت لە productsـدان، بڕەکان لە salesـدا. INNER JOIN هەر فرۆشتنێک لە تەنیشت کاڵاکەی دادەنێت (لێکبەستنەکان)؛ پاشان GROUP BY لەسەر کار دەکات. AS s و AS p کورتن بۆ :
SELECT p.brand, COUNT(*) AS sales, SUM(s.quantity) AS items_sold
FROM sales AS s
INNER JOIN products AS p ON s.product_id = p.product_id
GROUP BY p.brand
ORDER BY items_sold DESC, p.brand;+---------+-------+------------+ | brand | sales | items_sold | +---------+-------+------------+ | Samsung | 8 | 11 | | Xiaomi | 7 | 10 | | NULL | 2 | 3 | | Apple | 1 | 1 | | Asus | 1 | 1 | | Lenovo | 1 | 1 | +---------+-------+------------+ 6 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT p.category, SUM(s.quantity * p.price_iqd) AS revenue_iqd
FROM sales AS s
INNER JOIN products AS p ON s.product_id = p.product_id
GROUP BY p.category
ORDER BY revenue_iqd DESC;+------------+-------------+ | category | revenue_iqd | +------------+-------------+ | phone | 3165000 | | laptop | 1210000 | | charger | 330000 | | headphones | 190000 | +------------+-------------+ 4 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 1
The money of each sale is quantity × price;
SUMadds it up per category. (This uses today's prices; a real shop also stores the price paid insales.)پارەی هەر فرۆشتنێک بڕ × قیمەتە؛
SUMبۆ هەر جۆرێک کۆی دەکاتەوە. (ئەمە قیمەتەکانی ئەمڕۆ بەکار دەهێنێت؛ دوکانێکی ڕاستەقینە قیمەتی دراویش لەsalesـدا هەڵدەگرێت.)
Each seller earns a 2 % commission on what they sold, rounded to whole dinars — the textbook's commission example, now per seller:
هەر فرۆشیارێک 2 %ی ئەوەی فرۆشتوویەتی وەک کۆمیسیۆن وەردەگرێت، خڕکراوە بۆ دیناری تەواو — نموونەی کۆمیسیۆنی کتێبەکە، ئێستا بۆ هەر فرۆشیارێک:
SELECT s.seller,
SUM(s.quantity * p.price_iqd) AS sold_iqd,
ROUND(SUM(s.quantity * p.price_iqd) * 0.02) AS commission
FROM sales AS s
INNER JOIN products AS p ON s.product_id = p.product_id
GROUP BY s.seller
ORDER BY s.seller;+--------+----------+------------+ | seller | sold_iqd | commission | +--------+----------+------------+ | Lana | 2755000 | 55100 | | Rezan | 2140000 | 42800 | +--------+----------+------------+ 2 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives the same totals and the commission as 55100.0 and 42800.0.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite هەمان کۆکان و کۆمیسیۆن وەک 55100.0 و 42800.0 دەدات.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 3
A single-row function (
ROUND) around an aggregate (SUM): first the total per seller, then 2 %, then rounding.(
ROUND) بە دەوری (SUM): یەکەم کۆی هەر فرۆشیارێک، پاشان 2 %، پاشان خڕکردنەوە.
HAVING: keeping or dropping whole groupsHAVING: هێشتنەوە یان لابردنی گرووپی تەواو
WHERE filters rows before they are grouped. filters groups after GROUP BY, so it may use aggregates. The textbook's question which payment types were used more than twice? needs HAVING:
WHERE پێش گرووپکردن دەپاڵێوێت. دوای GROUP BY گرووپەکان دەپاڵێوێت، بۆیە دەتوانێت بەکار بهێنێت. پرسیاری کتێبەکە کام جۆری پارەدان زیاتر لە دوو جار بەکار هاتووە؟ پێویستی بە HAVINGـە:
SELECT payment, COUNT(*) AS times
FROM sales
GROUP BY payment
HAVING COUNT(*) > 2
ORDER BY payment;+---------+-------+ | payment | times | +---------+-------+ | cash | 10 | | fib | 8 | +---------+-------+ 2 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 4
cardwas used only twice, so its group is dropped.cardتەنها دوو جار بەکار هاتووە، بۆیە گرووپەکەی لادەبرێت.
An aggregate cannot go in WHERE, because when WHERE runs there are no groups yet:
ناتوانێت لە WHEREـدا بێت، چونکە کاتێک WHERE کار دەکات هێشتا هیچ گرووپێک نییە:
SELECT category FROM products WHERE COUNT(*) >= 2 GROUP BY category; -- wrongERROR 1111 (HY000): Invalid use of group function
MySQL's answer (from its error list). SQLite 3.51 says: misuse of aggregate: COUNT().
وەڵامی MySQL (لە لیستی هەڵەکانییەوە). SQLite 3.51 دەڵێت: misuse of aggregate: COUNT().
A condition on rows and a condition on groups can work together. Cash sales per seller, only for sellers with at least three of them:
لەسەر و لەسەر گرووپەکان دەتوانن پێکەوە کار بکەن. فرۆشتنی نەختینە بۆ هەر فرۆشیارێک، تەنها بۆ ئەو فرۆشیارانەی لانیکەم سێیان هەیە:
SELECT seller, COUNT(*) AS cash_sales
FROM sales
WHERE payment = 'cash'
GROUP BY seller
HAVING COUNT(*) >= 3
ORDER BY seller;+--------+------------+ | seller | cash_sales | +--------+------------+ | Rezan | 8 | +--------+------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 3-5
WHEREkeeps the 10 cash sales; grouping gives Lana 2 and Rezan 8;HAVINGdrops Lana's group.WHERE10 فرۆشتنە نەختینەکە دەهێڵێتەوە؛ گرووپکردن Lana 2 و Rezan 8 دەدات؛HAVINGگرووپی Lana لادەبات.
One more, from a database course's review notes: the average price of every category that has at least three products.
یەکێکی تر، لە تێبینییەکانی پێداچوونەوەی کۆرسێکی : تێکڕای قیمەتی هەر جۆرێک کە لانیکەم سێ کاڵای هەیە.
SELECT category, AVG(price_iqd) AS average_price
FROM products
GROUP BY category
HAVING COUNT(*) >= 3
ORDER BY category;+----------+---------------+ | category | average_price | +----------+---------------+ | charger | 24333.3333 | | laptop | 716666.6667 | | phone | 512500.0000 | +----------+---------------+ 3 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite gives 24333.333333333332, 716666.6666666666 and 512500.0.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite 24333.333333333332، 716666.6666666666 و 512500.0 دەدات.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 4
The headphones (2 products) are dropped. The averages show MySQL's four decimal places.
(2 کاڵا) لادەبرێن. تێکڕاکان چوار شوێنی دوای خاڵی MySQL پیشان دەدەن.
HAVING: keeping or dropping whole groupsHAVING: هێشتنەوە یان لابردنی گرووپی تەواو
Worked example, step by stepنموونەی شیکراوە، هەنگاو بە هەنگاو
For each category, find the cheapest product that costs at least 20,000 IQD — but only for categories that have at least two such products.
بۆ هەر جۆرێک، هەرزانترین ئەو کاڵایە بدۆزەرەوە کە لانیکەم 20,000 دینارە — بەڵام تەنها بۆ ئەو جۆرانەی لانیکەم دوو کاڵای وایان هەیە.
SELECT category, COUNT(*) AS how_many, MIN(price_iqd) AS cheapest
FROM products
WHERE price_iqd >= 20000
GROUP BY category
HAVING COUNT(*) >= 2
ORDER BY category;+----------+----------+----------+ | category | how_many | cheapest | +----------+----------+----------+ | charger | 2 | 25000 | | laptop | 3 | 600000 | | phone | 4 | 165000 | +----------+----------+----------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.


FROM — start with all 12 products.
FROM — بە هەموو 12 کاڵاکە دەست پێبکە.
WHERE
price_iqd >= 20000— the Fast Charger 33W (18,000) and the Wired Earphones (7,500) are removed; 10 rows are left.WHERE
price_iqd >= 20000— Fast Charger 33W (18,000) و Wired Earphones (7,500) لادەبرێن؛ 10 دەمێنێتەوە.GROUP BY
category— charger 2 rows, headphones 1, laptop 3, phone 4.GROUP BY
category— charger 2 ، headphones 1، laptop 3، phone 4.HAVING
COUNT(*) >= 2— the headphones group has only the Galaxy Buds FE, so it is dropped.HAVING
COUNT(*) >= 2— گرووپی headphones تەنها Galaxy Buds FEـی تێدایە، بۆیە لادەبرێت.SELECT — for each of the three groups left, write the category,
COUNT(*)andMIN(price_iqd).SELECT — بۆ هەر یەک لەو سێ گرووپەی ماونەتەوە، جۆر،
COUNT(*)وMIN(price_iqd)بنووسە.ORDER BY
category— sort the three answer rows.ORDER BY
category— سێ وەڵامەکە ڕیز بکە.
HAVING: keeping or dropping whole groupsHAVING: هێشتنەوە یان لابردنی گرووپی تەواو
Every row or some row: MAX and MIN in HAVINGهەموو تۆمارێک یان هەندێک تۆمار: MAX و MIN لە HAVING
Add one more wish: … and every product of the category costs at most 1,000,000 IQD. Standard SQL has an aggregate for every row is true, EVERY(price_iqd <= 1000000). MySQL and SQLite do not have it:
داواکارییەکی تر زیاد بکە: … و هەموو کاڵایەکی ئەو جۆرە لە 1,000,000 دینار زیاتر نییە. SQLـی ستاندارد بۆ هەموو ڕاستە هەیە، EVERY(price_iqd <= 1000000). MySQL و SQLite ئەوەیان نییە:
SELECT category, MIN(price_iqd) FROM products
WHERE price_iqd >= 20000
GROUP BY category
HAVING COUNT(*) >= 2 AND EVERY(price_iqd <= 1000000);Parse error: no such function: EVERY
SQLite's answer (sqlite3 shell; SQLite 3.51 gives the same error); MySQL also refuses the query, because it has no function EVERY.
وەڵامی SQLite (لە sqlite3ـدا؛ SQLite 3.51 هەمان هەڵە دەدات)؛ MySQLـیش ڕەت دەکاتەوە، چونکە EVERYـی نییە.
Think about it differently: every price is at most 1,000,000 means the largest price is at most 1,000,000. So write MAX(…) <= …:
بە شێوەیەکی تر بیری لێ بکەرەوە: هەموو قیمەتێک لە 1,000,000 زیاتر نییە واتە گەورەترین قیمەت لە 1,000,000 زیاتر نییە. بۆیە بنووسە MAX(…) <= …:
SELECT category, COUNT(*) AS how_many, MIN(price_iqd) AS cheapest
FROM products
WHERE price_iqd >= 20000
GROUP BY category
HAVING COUNT(*) >= 2 AND MAX(price_iqd) <= 1000000
ORDER BY category;+----------+----------+----------+ | category | how_many | cheapest | +----------+----------+----------+ | charger | 2 | 25000 | | laptop | 3 | 600000 | +----------+----------+----------+ 2 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 5
The phone group is dropped because the iPhone 15 costs 1,350,000.
گرووپی phone لادەبرێت چونکە iPhone 15 1,350,000 دینارە.
And at least one product costs at most 1,000,000 (standard ANY or SOME) means the smallest price is at most 1,000,000: MIN(…) <= …. Then the phone group stays, thanks to its cheaper phones:
و لانیکەم یەک کاڵا لە 1,000,000 زیاتر نییە (ANY یان SOMEـی ستاندارد) واتە بچووکترین قیمەت لە 1,000,000 زیاتر نییە: MIN(…) <= …. ئەو کاتە گرووپی phone دەمێنێتەوە، بەهۆی مۆبایلە هەرزانترەکانیەوە:
SELECT category, COUNT(*) AS how_many, MIN(price_iqd) AS cheapest
FROM products
WHERE price_iqd >= 20000
GROUP BY category
HAVING COUNT(*) >= 2 AND MIN(price_iqd) <= 1000000
ORDER BY category;+----------+----------+----------+ | category | how_many | cheapest | +----------+----------+----------+ | charger | 2 | 25000 | | laptop | 3 | 600000 | | phone | 4 | 165000 | +----------+----------+----------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
| You meanمەبەستت ئەمەیە | Standard SQLSQLـی ستاندارد | Write in MySQL and SQLiteلە MySQL و SQLite بنووسە |
|---|---|---|
every row of the group has x <= vهەموو گرووپەکە x <= vـی هەیە | EVERY(x <= v) | MAX(x) <= v |
some row of the group has x <= vهەندێک گرووپەکە x <= vـی هەیە | ANY / SOME | MIN(x) <= v |
every row has x >= vهەموو x >= vـی هەیە | EVERY(x >= v) | MIN(x) >= v |
some row has x >= vهەندێک x >= vـی هەیە | ANY / SOME | MAX(x) >= v |
HAVING: keeping or dropping whole groupsHAVING: هێشتنەوە یان لابردنی گرووپی تەواو
Filter before or after grouping?پێش یان دوای گرووپکردن بپاڵێوە؟
Is every product costs at most 1,000,000 the same as removing the expensive rows first with WHERE? Try it:
ئایا هەموو کاڵایەک لە 1,000,000 زیاتر نییە هەمان لابردنی کاڵا گرانەکانە بە WHERE لە سەرەتادا؟ تاقی بکەرەوە:
SELECT category, COUNT(*) AS how_many, MIN(price_iqd) AS cheapest
FROM products
WHERE price_iqd BETWEEN 20000 AND 1000000
GROUP BY category
HAVING COUNT(*) >= 2
ORDER BY category;+----------+----------+----------+ | category | how_many | cheapest | +----------+----------+----------+ | charger | 2 | 25000 | | laptop | 3 | 600000 | | phone | 3 | 165000 | +----------+----------+----------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
No. WHERE throws away the iPhone row before grouping, so the phone group still has three cheaper phones and stays. With MAX(price_iqd) <= 1000000 in HAVING, the whole phone group is judged and dropped. On this data the WHERE version gives the same rows as the some row (MIN) version — but only by chance.
نەخێر. WHERE iPhone پێش گرووپکردن فڕێ دەدات، بۆیە گرووپی phone هێشتا سێ مۆبایلی هەرزانتری تێدایە و دەمێنێتەوە. لەگەڵ MAX(price_iqd) <= 1000000 لە HAVING، هەموو گرووپی phone هەڵدەسەنگێنرێت و لادەبرێت. لەسەر ئەم شێوەی WHERE هەمان شێوەی هەندێک (MIN) دەدات — بەڵام تەنها بە ڕێکەوت.
| Versionشێوە | Phone groupگرووپی phone | Answerوەڵام |
|---|---|---|
HAVING … AND MAX(price_iqd) <= 1000000 | dropped (the iPhone is in the group)لادەبرێت (iPhone لە گرووپەکەدایە) | charger, laptop |
HAVING … AND MIN(price_iqd) <= 1000000 | kept with 4 rowsبە 4 دەمێنێتەوە | charger, laptop, phone |
WHERE price_iqd BETWEEN 20000 AND 1000000 | kept with 3 rows (the iPhone was removed first)بە 3 دەمێنێتەوە (iPhone لە سەرەتادا لابرا) | charger, laptop, phone |
The whole SELECT, and the order SQL reads itهەموو SELECT و ئەو ڕیزبەندییەی SQL پێی دەخوێنێتەوە
Here is the full shape of a SELECT. The parts must be written in this order; the parts in square brackets are optional.
ئەمە شێوەی تەواوی . بەشەکان دەبێت بەم ڕیزبەندییە بنووسرێن؛ ئەو بەشانەی لە ناو کەوانەی چوارگۆشەدان هەڵبژاردەن.
SELECT [DISTINCT] columns, expressions, aggregates
FROM table(s)
[WHERE row condition]
[GROUP BY columns]
[HAVING group condition]
[ORDER BY columns [ASC | DESC]]
[LIMIT n];SQL does not read a query in the order it is written. Logically it works through these steps, each one handing a smaller table to the next:
SQL بەو ڕیزبەندییە ناخوێنێتەوە کە نووسراوە. بە شێوەی لۆجیکی بەم هەنگاوانەدا دەڕوات و هەر یەکێکیان بچووکتر دەداتە هەنگاوی دواتر:
FROM(and joins) — collect the rows.WHERE— keep the rows where the condition is true.GROUP BY— form the groups.HAVING— keep the groups where the condition is true.SELECT— compute the columns, the aggregates and the aliases.DISTINCT— remove repeated answer rows.ORDER BY— sort.LIMIT— cut the list.
FROM(و ) — کۆ دەکاتەوە.WHERE— ئەو دەهێڵێتەوە کە تێیاندا ڕاستە.GROUP BY— گرووپەکان دروست دەکات.HAVING— ئەو گرووپانە دەهێڵێتەوە کە تێیاندا ڕاستە.SELECT— ، و دەژمێرێت.DISTINCT— وەڵام لادەبات.ORDER BY— ڕیز دەکات.LIMIT— لیستەکە کورت دەکاتەوە.
The order a database works through a SELECT: FROM and JOIN, WHERE, GROUP BY, HAVING, SELECT, ORDER BY and LIMIT, animated step by step.
ئەو ڕیزبەندییەی پێ جێبەجێ دەکات: FROM و JOIN، WHERE، GROUP BY، HAVING، SELECT، ORDER BY و LIMIT، بە هەنگاو بە هەنگاو.
Whole video: the logical order FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT, and why the optimiser may reorder the real work.
هەموو ڤیدیۆکە: ڕیزبەندییە لۆجیکییەکە (FROM، WHERE، GROUP BY، HAVING، SELECT، ORDER BY، LIMIT) و بۆچی لەوانەیە کارە ڕاستەقینەکە بە ڕیزبەندییەکی تر بکات.
The whole SELECT, and the order SQL reads itهەموو SELECT و ئەو ڕیزبەندییەی SQL پێی دەخوێنێتەوە
Which parts are needed, and what the order explainsکام بەشانە پێویستن و ڕیزبەندییەکە چی ڕوون دەکاتەوە
Only SELECT is always needed. The table shows when each of the other parts is used:
تەنها SELECT هەمیشە پێویستە. خشتەکە پیشان دەدات هەر یەک لە بەشەکانی تر کەی بەکار دێت:
| Partبەش | Needed?پێویستە؟ | Its jobکارەکەی |
|---|---|---|
SELECT | alwaysهەمیشە | which columns and values the answer showsوەڵامەکە کام و نرخ پیشان دەدات |
FROM | when the data comes from a table (SELECT 2 + 3; needs none)کاتێک لە دێت (SELECT 2 + 3; پێویستی پێی نییە) | which tables (and joins)کام (و کام ) |
WHERE | noنەخێر | filters rows دەپاڵێوێت |
GROUP BY | for one answer per groupبۆ یەک وەڵام بۆ هەر گرووپێک | forms groupsگرووپ دروست دەکات |
HAVING | no (normally with GROUP BY)نەخێر (ئاسایی لەگەڵ GROUP BY) | filters groupsگرووپەکان دەپاڵێوێت |
ORDER BY | noنەخێر | sorts the answerوەڵامەکە ڕیز دەکات |
LIMIT | noنەخێر | keeps only the first rowsتەنها یەکەم دەهێڵێتەوە |
This order explains the rules of both SQL lessons: an alias cannot be used in WHERE (it is born at step 5) but can be used in ORDER BY (step 7); an aggregate cannot be used in WHERE (no groups yet) but can in HAVING, SELECT and ORDER BY. The database may use a faster plan inside, but the answer is always the same as if it had followed these steps. The most popular products, sorted by an aggregate alias:
ئەم ڕیزبەندییە یاساکانی هەردوو وانەی SQL ڕوون دەکاتەوە: لە WHEREـدا بەکار نایەت (لە هەنگاوی 5دا لەدایک دەبێت) بەڵام لە ORDER BYـدا بەکار دێت (هەنگاوی 7)؛ لە WHEREـدا بەکار نایەت (هێشتا هیچ گرووپێک نییە) بەڵام لە HAVING، SELECT و ORDER BYـدا بەکار دێت. لەوانەیە لە ناوەوە پلانێکی خێراتر بەکار بهێنێت، بەڵام وەڵامەکە هەمیشە وەک ئەوەیە کە ئەم هەنگاوانەی گرتبێتە بەر. بەناوبانگترین کاڵاکان، ڕیزکراو بەپێی :
SELECT p.name, SUM(s.quantity) AS sold
FROM sales AS s
INNER JOIN products AS p ON s.product_id = p.product_id
GROUP BY p.product_id, p.name
ORDER BY sold DESC, p.name
LIMIT 3;+-------------------+------+ | name | sold | +-------------------+------+ | USB-C Charger 25W | 6 | | Fast Charger 33W | 5 | | Galaxy A15 | 3 | +-------------------+------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 4
Grouping by the primary key
product_idkeeps two products with the same name apart;p.nameis added so that the name may be shown.گرووپکردن بەپێی
product_idدوو کاڵا بە هەمان ناو لە یەک جیا دەهێڵێتەوە؛p.nameزیاد کراوە بۆ ئەوەی ناوەکە پیشان بدرێت.
Where you will meet this againلە کوێ دووبارە ئەمە دەبینیتەوە
Grouping is everywhere that data is summarised:
گرووپکردن لە هەموو ئەو شوێنانەدایە کە کورت دەکرێتەوە:
- Microsoft Access builds the same queries without typing: a totals query is
GROUP BYwith aggregates, and the Find Duplicates wizard writesGROUP BY … HAVING COUNT(*) > 1. In our shop, the cities with more than one customer:
- Microsoft Access هەمان بەبێ نووسین دروست دەکات: پرسی کۆکردنەوە هەمان
GROUP BYـە لەگەڵ و یاریدەدەری Find Duplicates دەنووسێتGROUP BY … HAVING COUNT(*) > 1. لە دوکانەکەماندا، ئەو شارانەی زیاتر لە یەک کڕیاریان هەیە:
SELECT city, COUNT(*) AS customers
FROM customers
GROUP BY city
HAVING COUNT(*) > 1;+-----------+-----------+ | city | customers | +-----------+-----------+ | Sulaimani | 2 | +-----------+-----------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
- PHP reports. A grouped query returns ordinary rows, so a PHP page reads them with the same loop as any
SELECT(reading rows, SELECT and a while loop). - Database theory. Students who took every course is relational division; in SQL it is solved with
GROUP BYandHAVING COUNT(…)(division, the algebra examples in SQL). - Python has the same idea for lists:
sum(),min()andmax()(sum, max and min). - Statistics.
AVGis the arithmetic mean; a weighted mean such as an average mark weighted by course hours isSUM(mark * hours) / SUM(hours)(the weighted mean).
- ڕاپۆرتەکانی PHP. گرووپکراو ئاسایی دەگەڕێنێتەوە، بۆیە پەڕەیەکی PHP بە هەمان خول وەک هەر
SELECTـێک دەیانخوێنێتەوە (خوێندنەوەی تۆمارەکان، SELECT و خولێکی while). - تیۆری . ئەو خوێندکارانەی هەموو وانەیەکیان وەرگرتووە دابەشکردنی پەیوەندییە؛ لە SQLـدا بە
GROUP BYوHAVING COUNT(…)چارەسەر دەکرێت (دابەشکردن، نموونەکانی جەبر لە SQL). - Python هەمان بیرۆکەی بۆ لیست هەیە:
sum()،min()وmax()(sum، max و min). - ئامار.
AVGژمێرەییە؛ وەک تێکڕای نمرە کە بەپێی کاتژمێری وانەکان قورس کراوەSUM(mark * hours) / SUM(hours)ـە (ناوەندی قورسکراو).
Exercisesڕاهێنانەکان
All tasks use the shop database. They follow the exercise ideas of the course's textbook chapter and lecture slides, moved to our shop.
هەموو ئەرکەکان دوکانەکە بەکار دەهێنن. بیرۆکەی ڕاهێنانەکانی بەشی کتێبەکە و سلایدەکانی وانەی کۆرسەکە دەگرنەبەر کە گوازراونەتەوە بۆ دوکانەکەمان.
1. Name a function for each job: (a) the weekday name of 21 March 1991, (b) a number of characters from a given position of a text, (c) the name of the month you were born in, (d) your name in capital letters.
1. بۆ هەر کارێک ناو بهێنە: (أ) ناوی ڕۆژی هەفتەی 21ی ئازاری 1991، (ب) چەند لە شوێنێکی دیاریکراوی دەقێکەوە، (ج) ناوی ئەو مانگەی تێیدا لەدایک بوویت، (د) ناوەکەت بە پیتی گەورە.
Show answerوەڵامەکە پیشان بدە
- (a)
DAYNAME('1991-03-21')(b)SUBSTRING(), also writtenSUBSTR()orMID()(c)MONTHNAME()(d)UPPER()orUCASE().
- (أ)
DAYNAME('1991-03-21')(ب)SUBSTRING()، کە بەSUBSTR()یانMID()ـیش دەنووسرێت (ج)MONTHNAME()(د)UPPER()یانUCASE().
2. Predict what MySQL prints, then check in phpMyAdmin: SELECT POW(2, 3), ROUND(342.9234, -1), LENGTH('Information Technology'); — SELECT YEAR('1991-03-21'), MONTH('1991-03-21'), DAY('1991-03-21'), MONTHNAME('1991-03-21'), DAYNAME('1991-03-21'); — SELECT LEFT('Kurdistan', 4), RIGHT('Sulaimani', 4), MID('Halabja', 3, 3), SUBSTR('Erbil', 3);
2. پێشبینی بکە MySQL چی چاپ دەکات، پاشان لە phpMyAdmin بیپشکنە: SELECT POW(2, 3), ROUND(342.9234, -1), LENGTH('Information Technology'); — SELECT YEAR('1991-03-21'), MONTH('1991-03-21'), DAY('1991-03-21'), MONTHNAME('1991-03-21'), DAYNAME('1991-03-21'); — SELECT LEFT('Kurdistan', 4), RIGHT('Sulaimani', 4), MID('Halabja', 3, 3), SUBSTR('Erbil', 3);
Show answerوەڵامەکە پیشان بدە
SELECT POW(2, 3), ROUND(342.9234, -1), LENGTH('Information Technology');+-----------+---------------------+----------------------------------+
| POW(2, 3) | ROUND(342.9234, -1) | LENGTH('Information Technology') |
+-----------+---------------------+----------------------------------+
| 8 | 340 | 22 |
+-----------+---------------------+----------------------------------+
1 row in setMySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
SELECT YEAR('1991-03-21'), MONTH('1991-03-21'), DAY('1991-03-21'),
MONTHNAME('1991-03-21'), DAYNAME('1991-03-21');+--------------------+---------------------+-------------------+-------------------------+-----------------------+
| YEAR('1991-03-21') | MONTH('1991-03-21') | DAY('1991-03-21') | MONTHNAME('1991-03-21') | DAYNAME('1991-03-21') |
+--------------------+---------------------+-------------------+-------------------------+-----------------------+
| 1991 | 3 | 21 | March | Thursday |
+--------------------+---------------------+-------------------+-------------------------+-----------------------+
1 row in setMySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox).
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە).
SELECT LEFT('Kurdistan', 4), RIGHT('Sulaimani', 4), MID('Halabja', 3, 3), SUBSTR('Erbil', 3);+----------------------+-----------------------+----------------------+--------------------+
| LEFT('Kurdistan', 4) | RIGHT('Sulaimani', 4) | MID('Halabja', 3, 3) | SUBSTR('Erbil', 3) |
+----------------------+-----------------------+----------------------+--------------------+
| Kurd | mani | lab | bil |
+----------------------+-----------------------+----------------------+--------------------+
1 row in setMySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite's substr() gives the same four texts.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). substr()ـی SQLite هەمان چوار دەقەکە دەدات.
Information Technology has 22 characters, all English, so LENGTH and CHAR_LENGTH agree. 21 March 1991 — Newroz — was a Thursday.
Information Technology 22 هەیە، هەمووی ئینگلیزی، بۆیە LENGTH و CHAR_LENGTH وەک یەکن. 21ی ئازاری 1991 — نەورۆز — پێنجشەممە بوو.
3. (a) How many products does each brand have? (b) Without running them, predict the answers of: SELECT DISTINCT brand FROM products WHERE category = 'laptop';, SELECT COUNT(DISTINCT category) FROM products; and SELECT category, MAX(price_iqd), MIN(price_iqd) FROM products GROUP BY category ORDER BY category;
3. (أ) هەر براندێک چەند کاڵای هەیە؟ (ب) بەبێ جێبەجێکردن، پێشبینیی وەڵامی ئەمانە بکە: SELECT DISTINCT brand FROM products WHERE category = 'laptop';، SELECT COUNT(DISTINCT category) FROM products; و SELECT category, MAX(price_iqd), MIN(price_iqd) FROM products GROUP BY category ORDER BY category;
Show answerوەڵامەکە پیشان بدە
SELECT brand, COUNT(*) AS products
FROM products
GROUP BY brand
ORDER BY products DESC, brand;+---------+----------+ | brand | products | +---------+----------+ | Xiaomi | 4 | | Samsung | 3 | | Lenovo | 2 | | NULL | 1 | | Apple | 1 | | Asus | 1 | +---------+----------+ 6 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT DISTINCT brand FROM products WHERE category = 'laptop';+--------+ | brand | +--------+ | Lenovo | | Asus | +--------+ 2 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT COUNT(DISTINCT category) FROM products;+--------------------------+ | COUNT(DISTINCT category) | +--------------------------+ | 4 | +--------------------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT category, MAX(price_iqd), MIN(price_iqd)
FROM products
GROUP BY category
ORDER BY category;+------------+----------------+----------------+ | category | MAX(price_iqd) | MIN(price_iqd) | +------------+----------------+----------------+ | charger | 30000 | 18000 | | headphones | 95000 | 7500 | | laptop | 940000 | 600000 | | phone | 1350000 | 165000 | +------------+----------------+----------------+ 4 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
4. What is the average price of the Xiaomi products, and how many different brands of phone does the shop sell?
4. تێکڕای قیمەتی کاڵاکانی Xiaomi چەندە و دوکانەکە چەند براندی جیاوازی مۆبایل دەفرۆشێت؟
Show answerوەڵامەکە پیشان بدە
SELECT AVG(price_iqd) FROM products WHERE brand = 'Xiaomi';+----------------+ | AVG(price_iqd) | +----------------+ | 118875.0000 | +----------------+ 1 row in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite: 118875.0.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite: 118875.0.
SELECT COUNT(DISTINCT brand) FROM products WHERE category = 'phone';+-----------------------+ | COUNT(DISTINCT brand) | +-----------------------+ | 3 | +-----------------------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
5. Discounts (practise on a copy). Make a fresh copy of products and give it a column discount_iqd. Phones get no discount, laptops 10 % and everything else 5 %, rounded to whole dinars. Then find: (a) the most expensive laptop, (b) the average and the total discount of the Lenovo products, (c) how many products have no discount.
5. داشکاندن (لەسەر کۆپییەک ڕاهێنان بکە). کۆپییەکی نوێی products دروست بکە و discount_iqdـی پێ بدە. مۆبایل هیچ داشکاندنێکی نییە، 10 % و هەموو شتێکی تر 5 %، خڕکراوە بۆ دیناری تەواو. پاشان بیدۆزەرەوە: (أ) گرانترین ، (ب) تێکڕا و کۆی داشکاندنی کاڵاکانی Lenovo، (ج) چەند کاڵا هیچ داشکاندنێکیان نییە.
Show answerوەڵامەکە پیشان بدە
DROP TABLE IF EXISTS products_copy;
CREATE TABLE products_copy AS SELECT * FROM products;
ALTER TABLE products_copy ADD discount_iqd INT;
UPDATE products_copy SET discount_iqd = 0 WHERE category = 'phone';
UPDATE products_copy SET discount_iqd = ROUND(price_iqd * 0.10) WHERE category = 'laptop';
UPDATE products_copy SET discount_iqd = ROUND(price_iqd * 0.05) WHERE category NOT IN ('phone', 'laptop');Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 3
ALTER TABLE … ADDadds a column to an existing table; every row getsNULLuntil the updates fill it in.ALTER TABLE … ADDبۆ هەبوو زیاد دەکات؛ هەمووNULLوەردەگرێت تا UPDATEـەکان پڕی دەکەنەوە.
-- (a)
SELECT name, price_iqd FROM products_copy
WHERE category = 'laptop'
AND price_iqd = (SELECT MAX(price_iqd) FROM products_copy WHERE category = 'laptop');+--------------+-----------+ | name | price_iqd | +--------------+-----------+ | ThinkPad E14 | 940000 | +--------------+-----------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
-- (b)
SELECT AVG(discount_iqd), SUM(discount_iqd) FROM products_copy WHERE brand = 'Lenovo';+-------------------+-------------------+ | AVG(discount_iqd) | SUM(discount_iqd) | +-------------------+-------------------+ | 77500.0000 | 155000 | +-------------------+-------------------+ 1 row in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite: 77500.0 | 155000.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite: 77500.0 | 155000.
-- (c)
SELECT COUNT(*) FROM products_copy WHERE discount_iqd = 0;+----------+ | COUNT(*) | +----------+ | 4 | +----------+ 1 row in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
The ThinkPad (940,000 IQD) is the most expensive laptop; the Lenovo discounts are 61,000 and 94,000. Note that the condition of (a) must be repeated inside the subquery — otherwise it would look for a laptop costing 1,350,000, the price of the iPhone.
ThinkPad (940,000 دینار) گرانترین ؛ داشکاندنەکانی Lenovo 61,000 و 94,000ـن. سەرنج بدە کە (أ) دەبێت لە ناو دووبارە بکرێتەوە — دەنا بەدوای دەگەڕێت کە 1,350,000 دینار بێت، قیمەتی iPhone.
6. The shop raises all Xiaomi prices by 12 %, rounded to the nearest thousand dinars. Write the UPDATE (on the copy) and say what the new prices are.
6. دوکانەکە هەموو قیمەتەکانی Xiaomi بە 12 % بەرز دەکاتەوە، خڕکراوە بۆ نزیکترین هەزار دینار. UPDATEـەکە بنووسە (لەسەر کۆپییەکە) و بڵێ قیمەتە نوێیەکان چەندن.
Show answerوەڵامەکە پیشان بدە
UPDATE products_copy SET price_iqd = ROUND(price_iqd * 1.12, -3) WHERE brand = 'Xiaomi';
SELECT name, price_iqd FROM products_copy WHERE brand = 'Xiaomi';+------------------+-----------+ | name | price_iqd | +------------------+-----------+ | Redmi 13C | 185000 | | Redmi Note 13 | 319000 | | Fast Charger 33W | 20000 | | Wired Earphones | 8000 | +------------------+-----------+ 4 rows in set
MySQL's answer, worked out by hand from the MySQL 8.4 manual's rules (there is no MySQL server in our test sandbox). SQLite would store 184800, 319200, 20160 and 8400, because it ignores −3.
وەڵامی MySQL، بە دەست و بەپێی یاساکانی ڕێبەری MySQL 8.4 دەرهێنراوە (لە ژینگەی تاقیکردنەوەماندا MySQL نییە). SQLite 184800، 319200، 20160 و 8400 هەڵدەگرێت، چونکە −3 پشتگوێ دەخات.
7. How many purchases did each customer make? Which customers made more than three?
7. هەر کڕیارێک چەند جار کڕینی کردووە؟ کام کڕیار زیاتر لە سێ جار؟
Show answerوەڵامەکە پیشان بدە
SELECT customer_id, COUNT(*) AS purchases
FROM sales
GROUP BY customer_id
ORDER BY customer_id;+-------------+-----------+ | customer_id | purchases | +-------------+-----------+ | 1 | 4 | | 2 | 4 | | 3 | 4 | | 4 | 3 | | 5 | 3 | | 6 | 2 | +-------------+-----------+ 6 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
SELECT customer_id, COUNT(*) AS purchases
FROM sales
GROUP BY customer_id
HAVING COUNT(*) > 3
ORDER BY customer_id;+-------------+-----------+ | customer_id | purchases | +-------------+-----------+ | 1 | 4 | | 2 | 4 | | 3 | 4 | +-------------+-----------+ 3 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
Customers 1, 2 and 3 are Aram, Shilan and Karwan. To print their names, join customers and group by c.customer_id, c.name.
کڕیارەکانی 1، 2 و 3 Aram، Shilan و Karwanـن. بۆ چاپکردنی ناوەکانیان customers ببەستەوە و بەپێی c.customer_id, c.name گرووپ بکە.
8. Which products have never been sold?
8. کام کاڵا هەرگیز نەفرۆشراوە؟
Show answerوەڵامەکە پیشان بدە
SELECT name FROM products
WHERE product_id NOT IN (SELECT product_id FROM sales);+-----------------+ | name | +-----------------+ | ThinkPad E14 | | Wired Earphones | +-----------------+ 2 rows in set
Run in SQLite 3.51 on our shop database (there is no MySQL server in our test sandbox); MySQL returns the same rows.
لە SQLite 3.51 لەسەر دوکانەکەمان جێبەجێ کرا (لە ژینگەی تاقیکردنەوەماندا MySQL نییە)؛ MySQL هەمان دەگەڕێنێتەوە.
This is safe because sales.product_id is NOT NULL. If the subquery could return a NULL, NOT IN would return no rows at all (the NOT IN and NULL surprise); a LEFT JOIN … WHERE s.sale_id IS NULL (outer joins) avoids the problem.
ئەمە سەلامەتە چونکە sales.product_id NOT NULLـە. ئەگەر بیتوانیایە NULL بگەڕێنێتەوە، NOT IN هیچ نەدەگەڕاندەوە (سەرسوڕمانی NOT IN و NULL)؛ LEFT JOIN … WHERE s.sale_id IS NULL (لێکبەستنە دەرەکییەکان) لەم کێشەیە دوور دەکەوێتەوە.
9. Explain in two sentences what ORDER BY and GROUP BY are for, and give two differences between single-row and aggregate functions.
9. بە دوو ڕستە ڕوون بکەرەوە ORDER BY و GROUP BY بۆ چین و دوو جیاوازی لە نێوان و بهێنەرەوە.
Show answerوەڵامەکە پیشان بدە
ORDER BYonly sorts the rows of the answer; the number of rows stays the same.GROUP BYputs rows with equal values into groups so that aggregates give one row per group — the answer usually has fewer rows.- A single-row function gives one result for every row and can be used in
WHERE; an aggregate gives one result for a group of rows and cannot be used inWHERE(useHAVING).
ORDER BYتەنها وەڵامەکە ڕیز دەکات؛ ژمارەی وەک خۆی دەمێنێتەوە.GROUP BYئەو نرخی یەکسانیان هەیە دەخاتە گرووپەوە بۆ ئەوەی بۆ هەر گرووپێک یەک بدەن — وەڵامەکە زۆرجار کەمتری هەیە.- بۆ هەموو یەک ئەنجام دەدات و لە
WHEREـدا بەکار دێت؛ بۆ گرووپێک یەک ئەنجام دەدات و لەWHEREـدا بەکار نایەت (HAVINGبەکار بهێنە).
Common mistakesهەڵە باوەکان
| Mistakeهەڵە | What happensچی ڕوودەدات | Fixچارەسەر |
|---|---|---|
WHERE COUNT(*) > 2 | ERROR 1111: Invalid use of group functionهەڵەی 1111: Invalid use of group function | HAVING COUNT(*) > 2 |
SELECT category, name, COUNT(*) … GROUP BY category | MySQL 8.4: ERROR 1055; MariaDB and SQLite: a random nameMySQL 8.4: ERROR 1055؛ MariaDB و SQLite: ناوێکی هەڕەمەکی | aggregate the column or add it to GROUP BY بخەرە ناو یان بیخەرە GROUP BY |
SELECT name, MAX(price_iqd) FROM products | MySQL 8.4: ERROR 1140; elsewhere a name that may be wrongMySQL 8.4: ERROR 1140؛ لە شوێنی تر ناوێک کە لەوانەیە هەڵە بێت | a subquery: WHERE price_iqd = (SELECT MAX(price_iqd) …): WHERE price_iqd = (SELECT MAX(price_iqd) …) |
COUNT(email) | skips NULL e-mails: 5, not 6 customers NULL پشتگوێ دەخات: 5، نەک 6 کڕیار | COUNT(*) to count rowsCOUNT(*) بۆ ژماردنی |
AVG(stock) | divides by the known values only (NULL is not 0)تەنها دابەشی نرخە زانراوەکان دەکات (NULL 0 نییە) | AVG(COALESCE(stock, 0)) only if a missing value really means 0AVG(COALESCE(stock, 0)) تەنها ئەگەر نرخی ون بە ڕاستی واتای 0 بێت |
SUM(quantity) when no row matchesSUM(quantity) کاتێک هیچ نەگونجێت | NULL, not 0NULL، نەک 0 | COALESCE(SUM(quantity), 0) |
LENGTH(name) on Kurdish textLENGTH(name) لەسەر دەقی کوردی | counts bytes: 10 for شیلان دەژمێرێت: 10 بۆ شیلان | CHAR_LENGTH(name) |
EVERY(price_iqd <= 1000000) | no such function in MySQL or SQLite وا لە MySQL یان SQLite نییە | MAX(price_iqd) <= 1000000 |
ROUND(x, -3) in SQLiteROUND(x, -3) لە SQLite | the −3 is ignored−3 پشتگوێ دەخرێت | round(x / 1000.0) * 1000 |
CONCAT(name, email) | NULL if the e-mail is NULL (MySQL)NULL ئەگەر NULL بێت (MySQL) | CONCAT_WS(' ', name, email) |
GROUP BY seller without ORDER BYGROUP BY seller بەبێ ORDER BY | MariaDB sorts the groups, MySQL 8 does notMariaDB گرووپەکان ڕیز دەکات، MySQL 8 نا | … GROUP BY seller ORDER BY seller |
Summary and reviewپوختە و پێداچوونەوە
- A single-row function gives one result per row (
ROUND,UPPER,YEAR) and can be used in SELECT, WHERE and ORDER BY. An aggregate function gives one result per group (COUNT,SUM,AVG,MIN,MAX) and is used in SELECT, HAVING and ORDER BY. ROUND(n, -3)rounds to thousands in MySQL (SQLite ignores negative places);MODandFLOORsplit amounts;POWERraises to a power.- Positions in text start at 1.
LENGTHcounts bytes andCHAR_LENGTHcharacters — a Kurdish letter is 2 bytes in UTF-8.INSTR+LEFT/SUBSTRINGsplit text;CONCATgives NULL if any part is NULL. - Date parts:
YEAR,MONTH,DAY,MONTHNAME,DAYNAME,DAYOFWEEK; they work in WHERE, for example to find Friday sales. COUNT(*)counts rows,COUNT(col)non-NULL values,COUNT(DISTINCT col)different values. Aggregates skip NULL; with no rows COUNT gives 0 and the others NULL. MIN and MAX work on text and dates.- With GROUP BY every plain column of SELECT must be grouped (MySQL 8.4 enforces it with ONLY_FULL_GROUP_BY). WHERE filters rows before grouping, HAVING filters groups after it; write every as
MAX(…) <=and some asMIN(…) <=. - Logical order:
FROM → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT.
- بۆ هەر یەک ئەنجام دەدات (
ROUND،UPPER،YEAR) و لە SELECT، WHERE و ORDER BY بەکار دێت. بۆ هەر گرووپێک یەک ئەنجام دەدات (COUNT،SUM،AVG،MIN،MAX) و لە SELECT، HAVING و ORDER BY بەکار دێت. ROUND(n, -3)لە MySQL بۆ هەزاران خڕ دەکاتەوە (SQLite شوێنی سالب پشتگوێ دەخات)؛MODوFLOORبڕەکان دابەش دەکەن؛POWERئەنجام دەدات.- شوێن لە دەقدا لە 1ـەوە دەست پێدەکات.
LENGTHدەژمێرێت وCHAR_LENGTH— پیتێکی کوردی لە UTF-8دا 2 .INSTR+LEFT/SUBSTRINGدەق لەت دەکەن؛CONCATNULL دەدات ئەگەر هەر بەشێک NULL بێت. - بەشەکانی بەروار:
YEAR،MONTH،DAY،MONTHNAME،DAYNAME،DAYOFWEEK؛ لە WHEREـدا کار دەکەن، بۆ نموونە بۆ دۆزینەوەی فرۆشتنەکانی هەینی. COUNT(*)دەژمێرێت،COUNT(col)ئەو نرخانەی NULL نین،COUNT(DISTINCT col)نرخە جیاوازەکان. NULL پشتگوێ دەخەن؛ بەبێ هیچ COUNT 0 دەدات و ئەوانی تر NULL. MIN و MAX لەسەر دەق و بەروار کار دەکەن.- لەگەڵ GROUP BY هەموو ئاسایی SELECT دەبێت گرووپ بکرێت (MySQL 8.4 بە ONLY_FULL_GROUP_BY ناچاری دەکات). WHERE پێش گرووپکردن دەپاڵێوێت، HAVING دوای ئەوە گرووپەکان؛ هەموو وەک
MAX(…) <=و هەندێک وەکMIN(…) <=بنووسە. - ڕیزبەندیی لۆجیکی:
FROM → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT.
What is the difference between WHERE and HAVING?جیاوازیی نێوان WHERE و HAVING چییە؟
WHERE keeps or removes single rows before grouping and cannot use aggregates. HAVING keeps or removes whole groups after GROUP BY and can use aggregates.
WHERE پێش گرووپکردن دەهێڵێتەوە یان لادەبات و ناتوانێت بەکار بهێنێت. HAVING دوای GROUP BY گرووپی تەواو دەهێڵێتەوە یان لادەبات و دەتوانێت بەکار بهێنێت.
Why does SELECT name, MAX(price_iqd) FROM products; fail in MySQL 8.4, and what do you write instead?بۆچی SELECT name, MAX(price_iqd) FROM products; لە MySQL 8.4 هەڵە دەدات و لە جیاتی ئەوە چی دەنووسیت؟
MAX gives one value, but name has twelve; ONLY_FULL_GROUP_BY refuses to pick one (ERROR 1140). Write SELECT name, price_iqd FROM products WHERE price_iqd = (SELECT MAX(price_iqd) FROM products);.
MAX یەک نرخ دەدات، بەڵام name دوازدە نرخی هەیە؛ ONLY_FULL_GROUP_BY ڕەت دەکاتەوە یەکێکیان هەڵبژێرێت (ERROR 1140). بنووسە SELECT name, price_iqd FROM products WHERE price_iqd = (SELECT MAX(price_iqd) FROM products);.
The laptops' stocks are 4, NULL and 5. What are COUNT(*), COUNT(stock) and AVG(stock)?کۆگای لاپتۆپەکان 4، NULL و 5ـە. COUNT(*)، COUNT(stock) و AVG(stock) چەندن؟
3, 2 and 4.5 (4.5000 in MySQL): the NULL is not counted and not averaged.
3، 2 و 4.5 (4.5000 لە MySQL): NULL نە دەژمێردرێت و نە تێکڕای لێ دەردەهێنرێت.
Why can ORDER BY use an aggregate alias such as sold, while WHERE cannot use any alias?بۆچی ORDER BY دەتوانێت نازناوی کردارێکی کۆکردنەوە وەک sold بەکار بهێنێت، لە کاتێکدا WHERE ناتوانێت هیچ نازناوێک بەکار بهێنێت؟
Aliases are made at the SELECT step, which comes after WHERE and before ORDER BY.
لە هەنگاوی SELECTـدا دروست دەکرێن، کە دوای WHERE و پێش ORDER BY دێت.
Videoڤیدیۆ
Watch a videoسەیری ڤیدیۆیەک بکە
A video that viewers liked a lot and praised in their comments, chosen for this lesson.ڤیدیۆیەک کە بینەران زۆریان پێ خۆش بووە و لە کۆمێنتەکانیاندا ستایشیان کردووە، بۆ ئەم وانەیە هەڵبژێردراوە.
GROUP BY in MySQL: one answer per group with SUM, MAX, MIN, AVG and COUNT, then HAVING to keep only some groups.
لە : یەک وەڵام بۆ هەر گرووپێک بە SUM، MAX، MIN، AVG و COUNT، پاشان بۆ هێشتنەوەی تەنها هەندێک گرووپ.
Whole video, MySQL: GROUP BY with aggregates 0:00, HAVING 3:19; the heart of this lesson in five minutes.
هەموو ڤیدیۆکە، بە : لەگەڵ لە 0:00 و لە 3:19؛ کرۆکی ئەم وانەیە لە پێنج خولەکدا.
Lesson complete!وانەکە تەواو بوو!
Well done. Review the key terms, then go on to the next lesson.دەستخۆش. سەیرێکی زاراوە سەرەکییەکان بکەرەوە، پاشان بڕۆ بۆ وانەی داهاتوو.
Key termsزاراوە سەرەکییەکان
Connecting PHP to MySQLپەیوەندیکردنی PHP بە MySQL
Related lecturesوانە پەیوەندیدارەکان
- Databases and SQL basicsبنکەدراوەکان و بنەماکانی SQL
- Inserting and selecting data with PHPزیادکردن و هەڵبژاردنی زانیاری بە PHP
- Relational Algebra and Relational Calculusجەبری پەیوەندیدار و ژمێرکاریی پەیوەندیدار
- Queriesپرسەکان
- Functionsکردارەکان
- ASCII and Character CodesASCII و کۆدەکانی نووسە
- The Arithmetic Mean and the Weighted Meanناوەند و ناوەندی قورسکراو
References and further readingسەرچاوەکان و خوێندنەوەی زیاتر
- MySQL 8.4 Reference Manual: Aggregate Function Descriptions
- MySQL 8.4 Reference Manual: MySQL Handling of GROUP BY (ONLY_FULL_GROUP_BY, ERROR 1055 and 1140, ANY_VALUE)
- MySQL 8.4 Reference Manual: String Functions and Operators (LENGTH, CHAR_LENGTH, SUBSTRING, INSTR, TRIM, CONCAT)
- MySQL 8.4 Reference Manual: Mathematical Functions (ROUND, POW, MOD, CEIL, FLOOR)
- MySQL 8.4 Reference Manual: Date and Time Functions
- MySQL 8.4 Reference Manual: Date and Time Literals (the deprecated relaxed delimiters)
- MySQL 8.4 Reference Manual: SELECT Statement (HAVING, aliases)
- MySQL 8.4 Error Reference: server error messages (1054, 1111)
- MariaDB Knowledge Base: SQL_MODE (default modes, ONLY_FULL_GROUP_BY)
- MariaDB Knowledge Base: GROUP BY
- SQLite: Built-In Scalar SQL Functions (round, length, octet_length, substr, trim, concat)
- SQLite: The SELECT statement (bare columns in an aggregate query)
- PostgreSQL documentation: Aggregate Functions (every, bool_and)
This lecture is a first edition. The Kurdish text and terminology are waiting for review by Kurdish IT teachers.ئەم وانەیە چاپی یەکەمە. دەقە کوردییەکە و زاراوەکانی چاوەڕێی پێداچوونەوەی مامۆستایانی کوردی بواری IT ن.