Querying and SQL Functions
Overview
This chapter extends Class XI SQL with single-row functions (math, text and date) that transform values, and aggregate functions that summarise many rows into one. Students learn to group rows with GROUP BY, filter groups with HAVING, sort with ORDER BY, and combine two related tables with an equi-join. All examples use one Indian office database (EMPLOYEE and DEPARTMENT) so that every output can be checked by hand.
The CBSE 2025-26 syllabus covers the whole chapter: math, text, date and aggregate functions, GROUP BY, HAVING, ORDER BY, and working with two tables using equi-join. The set operations UNION, INTERSECT and MINUS described in NCERT are not listed in the syllabus and are marked as enrichment here.
Learning outcomes
- Students will be able to distinguish single-row functions from aggregate functions and choose the right one for a task.
- Students will be able to use POWER(), ROUND() (including negative places) and MOD() and predict their output.
- Students will be able to apply text functions such as UPPER(), MID(), LEFT(), RIGHT(), INSTR(), LENGTH() and TRIM(), including nested calls.
- Students will be able to extract parts of dates with NOW(), DATE(), MONTH(), MONTHNAME(), YEAR(), DAY() and DAYNAME().
- Students will be able to summarise data with MAX(), MIN(), SUM(), AVG() and COUNT(), and explain how NULLs are handled.
- Students will be able to write queries using GROUP BY, HAVING and ORDER BY in the correct clause order, and explain WHERE vs HAVING.
- Students will be able to compute the degree and cardinality of a Cartesian product and write equi-joins in both WHERE and JOIN ... ON form using table aliases.
Lesson plan
Quick oral recap of Class XI SQL (SELECT, WHERE, BETWEEN, IN, LIKE, IS NULL). In the lab, students run the provided script to create the OFFICE database and draw both tables in their notebooks. Introduce the idea of a function with a board example: SELECT UPPER('goa');.
Board demonstration: run UPPER(Name) and MAX(Salary) on the same table and count the output rows. Then teach POWER, MOD (with negative numbers) and ROUND. Lab: students compute PF and odd amounts on EMPLOYEE.
Draw a place-value chart and solve ten ROUND() questions with positive, zero and negative places. Pair work: each student writes five ROUND() puzzles for a partner; verify answers in MySQL.
Write strings in numbered boxes on the board for MID/SUBSTR/LEFT/RIGHT/INSTR. Teach nesting by extracting first names and e-mail user names. Lab worksheet of 15 output-prediction questions, checked in MySQL. Show TRIM family with CONCAT('[',...,']') to make spaces visible.
Students run NOW() a few times to see it change. Use DOJ to find joining year, month name and weekday. Activity: each student finds the weekday of their own birth date with DAYNAME().
Rewrite LIKE conditions using LEFT/RIGHT/INSTR. Filter by month or weekday of joining. Discuss why an alias cannot be used in WHERE.
Compute MAX, MIN, SUM, AVG, COUNT by hand on the printed table, then confirm in MySQL. Board discussion: why AVG(Bonus) is 5300 and not 3312.5. Compare COUNT(*), COUNT(col) and COUNT(DISTINCT col).
Sort by one and two columns, mixed ASC/DESC, and by an alias or expression. Quick quiz: predict the first and last row of five ORDER BY queries.
Cut the printed EMPLOYEE table into strips and physically group them by DeptID; students compute group totals. Then write GROUP BY queries, add HAVING, and finally combine WHERE + GROUP BY + HAVING + ORDER BY. Board chart of writing order vs processing order.
Draw a 3-row x 2-row example on the board to show pairing. Students find degree and cardinality of EMPLOYEE x DEPARTMENT and check with COUNT(*).
Add the join condition to the Cartesian product and watch the rows fall from 32 to 8. Teach aliases, qualified names, extra conditions with AND, JOIN ... ON form, and joins with GROUP BY. Lab: STUDENT and HOUSE join practical.
Brief look at UNION/INTERSECT/EXCEPT (enrichment). Complete practical file entries for all 10 SQL tasks. Revision test with MCQs and output-prediction questions.
Notes
Revision and the sample database used in this chapter
In Class XI students learnt to create a database, define tables with CREATE TABLE, add rows with INSERT, and retrieve rows with SELECT ... FROM ... WHERE using relational operators, BETWEEN, IN, LIKE, IS NULL and the logical operators AND, OR, NOT. This chapter builds on that base. Students now learn to transform values with functions, summarise many rows into one, group rows, sort results and combine two tables in one query.
All examples in these notes use a small database called OFFICE with two related tables:
EMPLOYEE(EmpID, Name, Gender, DOJ, Salary, Bonus, DeptID): EmpID is the primary key. Bonus is NULL for three employees on purpose, so that NULL handling can be shown.DEPARTMENT(DeptID, DeptName, City): DeptID is the primary key.EMPLOYEE.DeptIDis a foreign key that refers to it. Department D04 (HR) has no employees yet.
Ask students to copy both tables into their notebooks before the first lesson. Every output in this chapter can be checked against them.
SELECT * FROM EMPLOYEE;
SELECT * FROM DEPARTMENT;+-------+--------------+--------+------------+--------+-------+--------+ | EmpID | Name | Gender | DOJ | Salary | Bonus | DeptID | +-------+--------------+--------+------------+--------+-------+--------+ | E101 | Aarav Sharma | M | 2015-03-12 | 52350 | 5000 | D01 | | E102 | Priya Nair | F | 2018-07-01 | 61200 | NULL | D03 | | E103 | Rohan Gupta | M | 2012-11-23 | 45800 | 3500 | D02 | | E104 | Meera Iyer | F | 2020-01-15 | 72500 | 8000 | D03 | | E105 | Kabir Singh | M | 2019-09-30 | 38750 | NULL | D01 | | E106 | Ananya Das | F | 2016-05-20 | 49500 | 4000 | D02 | | E107 | Vikram Rao | M | 2021-12-05 | 58000 | 6000 | D03 | | E108 | Sneha Patil | F | 2017-02-28 | 41250 | NULL | D01 | +-------+--------------+--------+------------+--------+-------+--------+ +--------+----------+-----------+ | DeptID | DeptName | City | +--------+----------+-----------+ | D01 | Sales | Mumbai | | D02 | Accounts | Delhi | | D03 | IT | Bengaluru | | D04 | HR | Kolkata | +--------+----------+-----------+
Give students the CREATE and INSERT script for these two tables on day one, so lab time is spent on queries, not typing data. A short recap quiz on WHERE, BETWEEN, LIKE and IS NULL helps before moving on.
SQL functions: single-row and multiple-row
A function in SQL takes one or more values, works on them and returns a result. MySQL functions fall into two families:
- Single-row functions (also called scalar functions) work on one value from one row at a time and return one result for every row. If the table has 8 rows, you get 8 results. Math, text and date functions belong here.
- Multiple-row functions (also called aggregate or group functions) take a whole set of rows and return one result for the set.
MAX(),MIN(),SUM(),AVG()andCOUNT()belong here.
Single-row functions can appear in the SELECT list, in WHERE, and in ORDER BY. Aggregate functions appear in the SELECT list and in HAVING, but never in WHERE.
| Point | Single-row function | Multiple-row (aggregate) function |
|---|---|---|
| Works on | One value of one row at a time | A group (set) of rows |
| Number of results | One per row | One per group |
| Examples | ROUND(), UPPER(), MID(), YEAR() | SUM(), AVG(), MAX(), MIN(), COUNT() |
| Allowed in WHERE? | Yes | No (use HAVING) |
| Used with GROUP BY? | Not required | Usually, to get one result per group |
SELECT Name, UPPER(Name) FROM EMPLOYEE WHERE DeptID = 'D02';
SELECT MAX(Salary) FROM EMPLOYEE WHERE DeptID = 'D02';+-------------+-------------+ | Name | UPPER(Name) | +-------------+-------------+ | Rohan Gupta | ROHAN GUPTA | | Ananya Das | ANANYA DAS | +-------------+-------------+ +-------------+ | MAX(Salary) | +-------------+ | 49500 | +-------------+
A quick board test: run each function on the 8-row EMPLOYEE table and count the output rows. 8 rows means single-row; 1 row means aggregate.
Math functions: POWER(), ROUND() and MOD()
Math (numeric) functions take numbers and return a number.
POWER(x, y)orPOW(x, y)returns x raised to the power y.POWER(2,3)is 8. A negative power gives a fraction:POWER(2,-2)is 0.25.ROUND(n, d)rounds n to d decimal places. If d is left out, it is taken as 0 and n is rounded to the nearest whole number. A value exactly halfway (such as 283.5) is rounded away from zero, so 283.5 becomes 284 and -7.5 becomes -8.MOD(a, b)returns the remainder when a is divided by b. MySQL also acceptsa % b. The sign of the result follows the dividend a, soMOD(-23,5)is -3.MOD(n, 0)returns NULL.
These functions can be applied to literal values or to numeric columns. When applied to a column, they run once for every row.
SELECT POWER(3,4), POWER(2,-2), POW(10,3);
SELECT ROUND(2912.564,1), ROUND(283.5), ROUND(-7.5);
SELECT MOD(23,5), MOD(-23,5), 23 % 5, MOD(7.5,2);+------------+-------------+-----------+ | POWER(3,4) | POWER(2,-2) | POW(10,3) | +------------+-------------+-----------+ | 81 | 0.25 | 1000 | +------------+-------------+-----------+ +-------------------+--------------+-------------+ | ROUND(2912.564,1) | ROUND(283.5) | ROUND(-7.5) | +-------------------+--------------+-------------+ | 2912.6 | 284 | -8 | +-------------------+--------------+-------------+ +-----------+------------+--------+------------+ | MOD(23,5) | MOD(-23,5) | 23 % 5 | MOD(7.5,2) | +-----------+------------+--------+------------+ | 3 | -3 | 3 | 1.5 | +-----------+------------+--------+------------+
Board papers often ask for the output of MOD() with a negative number. Teach the rule: the remainder takes the sign of the first argument.
ROUND() in depth: positive, zero and negative places
The second argument of ROUND() decides which digit is the last one kept.
- Positive d keeps d digits after the decimal point.
ROUND(8.449,2)looks at the third decimal digit (9), so the answer is 8.45. - d = 0 or missing rounds to a whole number.
ROUND(472.5)is 473. - Negative d rounds to the left of the decimal point. d = -1 rounds to the nearest 10, d = -2 to the nearest 100, d = -3 to the nearest 1000. The digits to the right of that position become 0.
For ROUND(15.193,-1): the tens digit is 1, the digit after it is 5, so we round up to 20. For ROUND(745,-2): the hundreds digit is 7, the next digit is 4, so the answer is 700.
In the query below, a 12% provident fund (PF) deduction is rounded to the nearest hundred rupees.
| Expression | Result | Reason |
|---|---|---|
| ROUND(2912.564, 1) | 2912.6 | 2nd decimal is 6, so round up |
| ROUND(8.449, 2) | 8.45 | 3rd decimal is 9, so round up |
| ROUND(-3.45, 1) | -3.5 | Halfway rounds away from zero |
| ROUND(472.5) | 473 | d missing, so nearest whole number |
| ROUND(15.193, -1) | 20 | Nearest 10; units digit 5 rounds up |
| ROUND(1567.89, -2) | 1600 | Nearest 100; tens digit 6 rounds up |
| ROUND(745, -2) | 700 | Nearest 100; tens digit 4 rounds down |
| ROUND(750, -3) | 1000 | Nearest 1000; hundreds digit 7 rounds up |
SELECT Name, Salary, ROUND(Salary * 0.12, -2) AS PF,
MOD(Salary, 1000) AS Odd_Amount
FROM EMPLOYEE;+--------------+--------+------+------------+ | Name | Salary | PF | Odd_Amount | +--------------+--------+------+------------+ | Aarav Sharma | 52350 | 6300 | 350 | | Priya Nair | 61200 | 7300 | 200 | | Rohan Gupta | 45800 | 5500 | 800 | | Meera Iyer | 72500 | 8700 | 500 | | Kabir Singh | 38750 | 4700 | 750 | | Ananya Das | 49500 | 5900 | 500 | | Vikram Rao | 58000 | 7000 | 0 | | Sneha Patil | 41250 | 5000 | 250 | +--------------+--------+------+------------+
Draw a place-value chart (thousands, hundreds, tens, units, tenths, hundredths) on the board and mark position d. Students then look only at the digit to its right.
Text functions I: changing case and finding length
Text (string) functions work on character data such as names, cities and e-mail IDs.
UPPER(s)orUCASE(s)converts every letter of s to capitals.LOWER(s)orLCASE(s)converts every letter to small letters.LENGTH(s)returns the number of characters in s. Spaces count as characters.LENGTH('NEW DELHI')is 9.
Digits, spaces and symbols are not changed by UPPER() or LOWER().
SELECT UPPER('Delhi Public School'), LCASE('MUMBAI'), LENGTH('NEW DELHI');
SELECT Name, UCASE(Name), LENGTH(Name) FROM EMPLOYEE WHERE DeptID = 'D03';+------------------------------+-----------------+---------------------+
| UPPER('Delhi Public School') | LCASE('MUMBAI') | LENGTH('NEW DELHI') |
+------------------------------+-----------------+---------------------+
| DELHI PUBLIC SCHOOL | mumbai | 9 |
+------------------------------+-----------------+---------------------+
+------------+-------------+--------------+
| Name | UCASE(Name) | LENGTH(Name) |
+------------+-------------+--------------+
| Priya Nair | PRIYA NAIR | 10 |
| Meera Iyer | MEERA IYER | 10 |
| Vikram Rao | VIKRAM RAO | 10 |
+------------+-------------+--------------+Strictly, LENGTH() in MySQL counts bytes. For plain English text this equals the number of characters, which is all the board syllabus expects.
Text functions II: MID(), SUBSTRING(), SUBSTR(), LEFT() and RIGHT()
These functions extract part of a string. Positions in MySQL strings start at 1, not 0.
MID(s, pos, n),SUBSTRING(s, pos, n)andSUBSTR(s, pos, n)are three names for the same function. They return n characters starting at position pos. If n is left out, they return everything from pos to the end.- A negative pos counts from the right end:
SUBSTR('INFORMATICS',-4,3)starts at the 4th character from the end (T) and returns TIC. pos= 0 returns an empty string.LEFT(s, n)returns the first n characters.RIGHT(s, n)returns the last n characters.
Worked trace for MID('INFORMATICS',3,4): I(1) N(2) F(3) O(4) R(5) M(6) A(7)..., so the answer is FORM.
SELECT MID('INFORMATICS',3,4), SUBSTRING('INFORMATICS',6),
SUBSTR('INFORMATICS',-4,3), MID('INFORMATICS',0,3);
SELECT LEFT('KOLKATA',3), RIGHT('CHENNAI',4), MID('COMPUTER',4);+------------------------+----------------------------+----------------------------+------------------------+
| MID('INFORMATICS',3,4) | SUBSTRING('INFORMATICS',6) | SUBSTR('INFORMATICS',-4,3) | MID('INFORMATICS',0,3) |
+------------------------+----------------------------+----------------------------+------------------------+
| FORM | MATICS | TIC | |
+------------------------+----------------------------+----------------------------+------------------------+
+-------------------+--------------------+-------------------+
| LEFT('KOLKATA',3) | RIGHT('CHENNAI',4) | MID('COMPUTER',4) |
+-------------------+--------------------+-------------------+
| KOL | NNAI | PUTER |
+-------------------+--------------------+-------------------+Ask students to write the string in boxes with position numbers above each letter before answering any MID/SUBSTR output question. It removes nearly all errors.
Text functions III: INSTR() and combining functions
INSTR(s, sub) returns the position of the first occurrence of sub inside s. It returns 0 if sub is not found (not NULL, not -1). With MySQL's default settings, the search ignores case, so INSTR('Informatics','MA') is 6.
Functions can be nested: the output of one becomes the input of another. MySQL evaluates the innermost function first. A common use is to split a full name at the space:
INSTR(Name, ' ')gives the position of the space.LEFT(Name, INSTR(Name,' ') - 1)takes every character before the space, which is the first name.
The same idea extracts the user name from an e-mail ID (everything before '@').
SELECT INSTR('BANANA','NA'), INSTR('BANANA','XY'), INSTR('Informatics','MA');
SELECT Name, INSTR(Name,' ') AS SpaceAt,
LEFT(Name, INSTR(Name,' ') - 1) AS FirstName
FROM EMPLOYEE WHERE DeptID = 'D01';+----------------------+----------------------+---------------------------+
| INSTR('BANANA','NA') | INSTR('BANANA','XY') | INSTR('Informatics','MA') |
+----------------------+----------------------+---------------------------+
| 3 | 0 | 6 |
+----------------------+----------------------+---------------------------+
+--------------+---------+-----------+
| Name | SpaceAt | FirstName |
+--------------+---------+-----------+
| Aarav Sharma | 6 | Aarav |
| Kabir Singh | 6 | Kabir |
| Sneha Patil | 6 | Sneha |
+--------------+---------+-----------+Nested-function output questions are common for 2 or 3 marks. Train students to solve from the inside out and write each intermediate value.
Trimming spaces: LTRIM(), RTRIM() and TRIM()
Data typed by people often has extra spaces at the start or end. Leading spaces make comparisons fail (' Pune' = 'Pune' is false), and any extra space changes the value of LENGTH().
LTRIM(s)removes leading spaces (on the left).RTRIM(s)removes trailing spaces (on the right).TRIM(s)removes both leading and trailing spaces.
Spaces inside the string (between words) are never removed by any of these. In the example, square brackets are joined to the result with CONCAT() only to make the remaining spaces visible.
SELECT CONCAT('[', LTRIM(' Pune '), ']'),
CONCAT('[', RTRIM(' Pune '), ']'),
CONCAT('[', TRIM(' Pune '), ']');
SELECT LENGTH(' Goa '), LENGTH(LTRIM(' Goa ')), LENGTH(TRIM(' Goa '));+--------------------------------------+--------------------------------------+-------------------------------------+
| CONCAT('[', LTRIM(' Pune '), ']') | CONCAT('[', RTRIM(' Pune '), ']') | CONCAT('[', TRIM(' Pune '), ']') |
+--------------------------------------+--------------------------------------+-------------------------------------+
| [Pune ] | [ Pune] | [Pune] |
+--------------------------------------+--------------------------------------+-------------------------------------+
+-------------------+--------------------------+-------------------------+
| LENGTH(' Goa ') | LENGTH(LTRIM(' Goa ')) | LENGTH(TRIM(' Goa ')) |
+-------------------+--------------------------+-------------------------+
| 7 | 5 | 3 |
+-------------------+--------------------------+-------------------------+Output questions usually wrap trim functions inside LENGTH(). Count the spaces on each side carefully: ' Goa ' has 2 + 3 + 2 = 7 characters.
Date functions: NOW(), DATE(), MONTH(), MONTHNAME(), YEAR(), DAY(), DAYNAME()
MySQL stores dates as 'YYYY-MM-DD' and date-times as 'YYYY-MM-DD HH:MM:SS'. Date functions extract parts of these values.
NOW()returns the current date and time of the server, such as 2025-08-15 10:30:45. Its output changes every time you run it.DATE(dt)returns only the date part of a date-time.MONTH(d)returns the month number (1 to 12).MONTHNAME(d)returns the full month name, such as August.YEAR(d)returns the 4-digit year.DAY(d)returns the day of the month (1 to 31).DAYNAME(d)returns the weekday name, such as Friday.
MONTH(), YEAR() and DAY() return numbers; MONTHNAME() and DAYNAME() return text.
SELECT DATE('2025-08-15 10:30:45'), MONTH('2025-08-15'), MONTHNAME('2025-08-15'),
YEAR('2025-08-15'), DAY('2025-08-15'), DAYNAME('2025-08-15');
SELECT Name, DOJ, YEAR(DOJ), MONTHNAME(DOJ), DAYNAME(DOJ) FROM EMPLOYEE;+-----------------------------+---------------------+-------------------------+--------------------+-------------------+-----------------------+
| DATE('2025-08-15 10:30:45') | MONTH('2025-08-15') | MONTHNAME('2025-08-15') | YEAR('2025-08-15') | DAY('2025-08-15') | DAYNAME('2025-08-15') |
+-----------------------------+---------------------+-------------------------+--------------------+-------------------+-----------------------+
| 2025-08-15 | 8 | August | 2025 | 15 | Friday |
+-----------------------------+---------------------+-------------------------+--------------------+-------------------+-----------------------+
+--------------+------------+-----------+----------------+--------------+
| Name | DOJ | YEAR(DOJ) | MONTHNAME(DOJ) | DAYNAME(DOJ) |
+--------------+------------+-----------+----------------+--------------+
| Aarav Sharma | 2015-03-12 | 2015 | March | Thursday |
| Priya Nair | 2018-07-01 | 2018 | July | Sunday |
| Rohan Gupta | 2012-11-23 | 2012 | November | Friday |
| Meera Iyer | 2020-01-15 | 2020 | January | Wednesday |
| Kabir Singh | 2019-09-30 | 2019 | September | Monday |
| Ananya Das | 2016-05-20 | 2016 | May | Friday |
| Vikram Rao | 2021-12-05 | 2021 | December | Sunday |
| Sneha Patil | 2017-02-28 | 2017 | February | Tuesday |
+--------------+------------+-----------+----------------+--------------+Since NOW() changes every second, board questions show its output as "current date and time". Accept any correctly formatted date-time in answers. DATE(NOW()) gives today's date only.
Using single-row functions in WHERE and ORDER BY
Because single-row functions give a value for every row, they can be used to filter and sort rows.
- Employees who joined in the first half of any year:
WHERE MONTH(DOJ) BETWEEN 1 AND 6. - Names that start with A:
WHERE LEFT(Name,1) = 'A'(the same asLIKE 'A%'). - Employees who joined on a Friday:
WHERE DAYNAME(DOJ) = 'Friday'.
A column alias created with AS can be used in ORDER BY, but not in WHERE, because WHERE is processed before the SELECT list is built.
SELECT Name, DOJ FROM EMPLOYEE
WHERE MONTH(DOJ) BETWEEN 1 AND 6
ORDER BY Name;
SELECT Name, DAYNAME(DOJ) AS JoinDay FROM EMPLOYEE
WHERE DAYNAME(DOJ) = 'Friday';+--------------+------------+ | Name | DOJ | +--------------+------------+ | Aarav Sharma | 2015-03-12 | | Ananya Das | 2016-05-20 | | Meera Iyer | 2020-01-15 | | Sneha Patil | 2017-02-28 | +--------------+------------+ +-------------+---------+ | Name | JoinDay | +-------------+---------+ | Rohan Gupta | Friday | | Ananya Das | Friday | +-------------+---------+
Ask students to rewrite LIKE conditions using LEFT(), RIGHT() or INSTR() and compare. It builds understanding of both.
Aggregate functions: MAX(), MIN(), SUM(), AVG() and COUNT()
Aggregate functions summarise a column over many rows and return a single value.
MAX(col)andMIN(col)return the largest and smallest value. They work on numbers, dates (latest and earliest) and text (alphabetically last and first).SUM(col)returns the total.AVG(col)returns the average. Both work only on numbers.COUNT(col)returns how many values are present in the column.
All aggregate functions ignore NULL values. AVG(Bonus) adds the 5 non-NULL bonuses and divides by 5, not by 8.
A WHERE clause filters rows before the aggregate is calculated. MySQL shows AVG() of whole numbers with 4 decimal places; use ROUND() to tidy it.
SELECT MAX(Salary), MIN(Salary), SUM(Salary), AVG(Salary) FROM EMPLOYEE;
SELECT MAX(DOJ), MIN(Name), SUM(Bonus), AVG(Bonus) FROM EMPLOYEE;
SELECT ROUND(AVG(Salary),2) AS Avg_IT FROM EMPLOYEE WHERE DeptID = 'D03';+-------------+-------------+-------------+-------------+ | MAX(Salary) | MIN(Salary) | SUM(Salary) | AVG(Salary) | +-------------+-------------+-------------+-------------+ | 72500 | 38750 | 419350 | 52418.7500 | +-------------+-------------+-------------+-------------+ +------------+--------------+------------+------------+ | MAX(DOJ) | MIN(Name) | SUM(Bonus) | AVG(Bonus) | +------------+--------------+------------+------------+ | 2021-12-05 | Aarav Sharma | 26500 | 5300.0000 | +------------+--------------+------------+------------+ +----------+ | Avg_IT | +----------+ | 63900.00 | +----------+
A favourite board trap: SELECT Name, MAX(Salary) FROM EMPLOYEE; Explain that Name has 8 values but MAX has one, so the query is invalid in standard SQL (MySQL with ONLY_FULL_GROUP_BY rejects it).
COUNT(*) vs COUNT(column) and NULL handling
COUNT() has three forms that give different answers when a column contains NULL or repeated values.
COUNT(*)counts rows, whatever they contain. EMPLOYEE has 8 rows, so the answer is 8.COUNT(col)counts the non-NULL values in that column. Bonus is NULL for 3 employees, soCOUNT(Bonus)is 5.COUNT(DISTINCT col)counts different non-NULL values. DeptID has 3 different values, so the answer is 3.
Because NULLs are skipped, AVG(Bonus) (26500 / 5 = 5300) is not the same as SUM(Bonus)/COUNT(*) (26500 / 8 = 3312.5). Choose the one that matches the question being asked.
| Expression | Result on EMPLOYEE | What it counts |
|---|---|---|
| COUNT(*) | 8 | All rows |
| COUNT(Bonus) | 5 | Rows where Bonus is not NULL |
| COUNT(DISTINCT DeptID) | 3 | Different DeptID values |
| COUNT(*) with WHERE Bonus IS NULL | 3 | Rows with no bonus |
SELECT COUNT(*), COUNT(Bonus), COUNT(DISTINCT DeptID) FROM EMPLOYEE;
SELECT AVG(Bonus), SUM(Bonus)/COUNT(*) FROM EMPLOYEE;
SELECT COUNT(*) AS No_Bonus FROM EMPLOYEE WHERE Bonus IS NULL;+----------+--------------+------------------------+ | COUNT(*) | COUNT(Bonus) | COUNT(DISTINCT DeptID) | +----------+--------------+------------------------+ | 8 | 5 | 3 | +----------+--------------+------------------------+ +------------+---------------------+ | AVG(Bonus) | SUM(Bonus)/COUNT(*) | +------------+---------------------+ | 5300.0000 | 3312.5000 | +------------+---------------------+ +----------+ | No_Bonus | +----------+ | 3 | +----------+
NULL is not zero. If NULL were 0, AVG(Bonus) would be 3312.5. Make students explain the difference in one sentence; this is a frequent 2-mark question.
Sorting results with ORDER BY
ORDER BY arranges the output rows. It is always the last clause of a query.
ASC(ascending) is the default: smallest number, earliest date, or A first.DESCsorts in descending order.- You can sort on more than one column. Rows are sorted by the first column; rows that tie on it are then sorted by the second column, and so on. Each column can have its own
ASCorDESC. - You can sort on an expression or an alias, for example
ORDER BY YEAR(DOJ)orORDER BY Total DESC.
Without ORDER BY, the order of rows in the output is not guaranteed.
SELECT Name, Salary FROM EMPLOYEE ORDER BY Salary DESC;
SELECT DeptID, Name, Salary FROM EMPLOYEE ORDER BY DeptID, Salary DESC;+--------------+--------+ | Name | Salary | +--------------+--------+ | Meera Iyer | 72500 | | Priya Nair | 61200 | | Vikram Rao | 58000 | | Aarav Sharma | 52350 | | Ananya Das | 49500 | | Rohan Gupta | 45800 | | Sneha Patil | 41250 | | Kabir Singh | 38750 | +--------------+--------+ +--------+--------------+--------+ | DeptID | Name | Salary | +--------+--------------+--------+ | D01 | Aarav Sharma | 52350 | | D01 | Sneha Patil | 41250 | | D01 | Kabir Singh | 38750 | | D02 | Ananya Das | 49500 | | D02 | Rohan Gupta | 45800 | | D03 | Meera Iyer | 72500 | | D03 | Priya Nair | 61200 | | D03 | Vikram Rao | 58000 | +--------+--------------+--------+
In the second query DeptID is ascending and Salary is descending. Students often think DESC applies to both; it applies only to the column just before it.
GROUP BY: one summary row per group
GROUP BY col collects rows that have the same value in col into a group, and then each aggregate function is calculated separately for each group. The output has one row per group.
Rules to remember:
- A column in the
SELECTlist must either be in theGROUP BYclause or be inside an aggregate function. WHERE(if present) removes rows before grouping.- You can group on an expression such as
YEAR(DOJ). - Rows with NULL in the grouping column form one group of their own.
The first query below gives the head count, salary bill and average salary of each department. The second counts how many employees joined each year from 2018 onwards.
SELECT DeptID, COUNT(*), SUM(Salary), ROUND(AVG(Salary),2)
FROM EMPLOYEE
GROUP BY DeptID
ORDER BY DeptID;
SELECT YEAR(DOJ) AS Yr, COUNT(*) FROM EMPLOYEE
WHERE YEAR(DOJ) >= 2018
GROUP BY YEAR(DOJ)
ORDER BY Yr;+--------+----------+-------------+----------------------+ | DeptID | COUNT(*) | SUM(Salary) | ROUND(AVG(Salary),2) | +--------+----------+-------------+----------------------+ | D01 | 3 | 132350 | 44116.67 | | D02 | 2 | 95300 | 47650.00 | | D03 | 3 | 191700 | 63900.00 | +--------+----------+-------------+----------------------+ +------+----------+ | Yr | COUNT(*) | +------+----------+ | 2018 | 1 | | 2019 | 1 | | 2020 | 1 | | 2021 | 1 | +------+----------+
Show grouping physically: sort the printed EMPLOYEE table by DeptID, draw a box around each department, and compute SUM and COUNT for each box by hand. Then run the query.
HAVING: filtering groups
HAVING puts a condition on groups, after GROUP BY has formed them and the aggregates are known. It is the only place where an aggregate function can be used in a condition.
- Departments whose average salary is above 50000:
GROUP BY DeptID HAVING AVG(Salary) > 50000. - A query can have both
WHEREandHAVING. In the second example,WHERE Gender = 'F'first keeps only female employees, then the remaining rows are grouped, thenHAVINGkeeps groups with at least one row, and finallyORDER BYsorts.
A condition that does not need an aggregate (such as DeptID <> 'D02') should go in WHERE, because removing rows early is simpler and faster.
SELECT DeptID, AVG(Salary) FROM EMPLOYEE
GROUP BY DeptID
HAVING AVG(Salary) > 50000;
SELECT DeptID, COUNT(*) FROM EMPLOYEE
WHERE Gender = 'F'
GROUP BY DeptID
HAVING COUNT(*) >= 1
ORDER BY DeptID DESC;+--------+-------------+ | DeptID | AVG(Salary) | +--------+-------------+ | D03 | 63900.0000 | +--------+-------------+ +--------+----------+ | DeptID | COUNT(*) | +--------+----------+ | D03 | 2 | | D02 | 1 | | D01 | 1 | +--------+----------+
WHERE vs HAVING, and the order of clauses
Clauses must be written in this fixed order:
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY
MySQL processes them in a different order, which explains most rules in this chapter:
FROM: pick the table(s); for two tables, form their combination.WHERE: keep only rows that satisfy the condition.GROUP BY: form groups.HAVING: keep only groups that satisfy the condition.SELECT: compute the output columns and aliases.ORDER BY: sort the final rows.
Since WHERE runs before groups exist, it cannot use aggregates. Since ORDER BY runs last, it can use aliases.
| Point | WHERE | HAVING |
|---|---|---|
| Filters | Individual rows | Groups formed by GROUP BY |
| When applied | Before grouping | After grouping |
| Aggregate functions allowed? | No | Yes |
| Needs GROUP BY? | No | Normally used with GROUP BY |
| Example | WHERE Salary > 50000 | HAVING SUM(Salary) > 100000 |
Write the mnemonic "Some Friends Want Good Hot Omelettes" for the writing order SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY.
Working with two tables: the Cartesian product
When two tables are listed in FROM with no condition linking them, MySQL pairs every row of the first table with every row of the second. This is the Cartesian product (also called cross product or cross join).
- Degree (number of columns) of the result = sum of the degrees. EMPLOYEE has 7 columns and DEPARTMENT has 3, so the result has 10 columns.
- Cardinality (number of rows) = product of the cardinalities: 8 x 4 = 32 rows.
Most of these 32 rows are meaningless (for example, an IT employee paired with the HR department). The Cartesian product is useful mainly as the starting point of a join, from which the matching rows are picked.
SELECT COUNT(*) FROM EMPLOYEE, DEPARTMENT;
SELECT E.Name, D.DeptName FROM EMPLOYEE E, DEPARTMENT D
WHERE E.EmpID = 'E101';+----------+ | COUNT(*) | +----------+ | 32 | +----------+ +--------------+----------+ | Name | DeptName | +--------------+----------+ | Aarav Sharma | Sales | | Aarav Sharma | Accounts | | Aarav Sharma | IT | | Aarav Sharma | HR | +--------------+----------+
Degree adds, cardinality multiplies. Board questions often give two table sizes and ask for both numbers.
Equi-join with WHERE, and table aliases
An equi-join keeps only those rows of the Cartesian product where the common column has equal values in both tables. The condition uses the equality operator =, hence the name.
- When both tables have a column with the same name (DeptID here), you must qualify it as
EMPLOYEE.DeptIDorDEPARTMENT.DeptID; otherwise MySQL reports an ambiguous column error. - A table alias is a short temporary name given in
FROM:FROM EMPLOYEE E, DEPARTMENT D. After that, writeE.DeptIDandD.DeptID. The alias exists only for that query. - Extra conditions are joined to the join condition with
AND.
Department D04 does not appear in the result because no employee has DeptID D04; an equi-join shows only matching rows.
SELECT E.Name, D.DeptName, D.City
FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DeptID = D.DeptID
ORDER BY E.EmpID;
SELECT E.Name, D.DeptName FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DeptID = D.DeptID AND D.City = 'Mumbai'
ORDER BY E.Name;+--------------+----------+-----------+ | Name | DeptName | City | +--------------+----------+-----------+ | Aarav Sharma | Sales | Mumbai | | Priya Nair | IT | Bengaluru | | Rohan Gupta | Accounts | Delhi | | Meera Iyer | IT | Bengaluru | | Kabir Singh | Sales | Mumbai | | Ananya Das | Accounts | Delhi | | Vikram Rao | IT | Bengaluru | | Sneha Patil | Sales | Mumbai | +--------------+----------+-----------+ +--------------+----------+ | Name | DeptName | +--------------+----------+ | Aarav Sharma | Sales | | Kabir Singh | Sales | | Sneha Patil | Sales | +--------------+----------+
Rule of thumb: to join n tables you need at least n - 1 join conditions. For two tables, one condition.
Equi-join with JOIN ... ON, and NATURAL JOIN
MySQL offers an explicit join syntax that keeps the join condition separate from the filter conditions:
SELECT ... FROM table1 JOIN table2 ON table1.col = table2.col WHERE ...;
JOIN and INNER JOIN mean the same thing. The result is identical to the WHERE form; many programmers prefer it because the join condition cannot be forgotten.
Joins combine naturally with functions, GROUP BY and HAVING. The first query below gives each department's name, staff strength and salary bill, highest bill first.
NATURAL JOIN joins on all columns with the same name and shows the common column only once. It is convenient, but risky if the tables share a column name by accident.
SELECT D.DeptName, COUNT(*) AS Staff, SUM(E.Salary) AS Payroll
FROM EMPLOYEE E JOIN DEPARTMENT D ON E.DeptID = D.DeptID
GROUP BY D.DeptName
ORDER BY Payroll DESC;
SELECT * FROM EMPLOYEE NATURAL JOIN DEPARTMENT WHERE DeptID = 'D02';+----------+-------+---------+ | DeptName | Staff | Payroll | +----------+-------+---------+ | IT | 3 | 191700 | | Sales | 3 | 132350 | | Accounts | 2 | 95300 | +----------+-------+---------+ +--------+-------+-------------+--------+------------+--------+-------+----------+-------+ | DeptID | EmpID | Name | Gender | DOJ | Salary | Bonus | DeptName | City | +--------+-------+-------------+--------+------------+--------+-------+----------+-------+ | D02 | E103 | Rohan Gupta | M | 2012-11-23 | 45800 | 3500 | Accounts | Delhi | | D02 | E106 | Ananya Das | F | 2016-05-20 | 49500 | 4000 | Accounts | Delhi | +--------+-------+-------------+--------+------------+--------+-------+----------+-------+
Students should be able to write the same join both ways. Practise converting a WHERE-form join to JOIN ... ON and back.
Set operations: UNION, INTERSECT and MINUS (Enrichment)
NCERT also describes operations that combine the results of two queries row-wise. They are not listed in the CBSE 2025-26 syllabus, so treat them as enrichment.
- Both queries must return the same number of columns with compatible data types.
UNIONreturns rows present in either result, removing duplicates.UNION ALLkeeps duplicates.INTERSECTreturns rows present in both results.MINUS(set difference) returns rows in the first result but not in the second. MySQL does not use the keywordMINUS; MySQL 8.0.31 and later useEXCEPT. Older MySQL versions support onlyUNION.
The example lists employees who are either in Accounts (D02) or earn more than 60000.
SELECT Name FROM EMPLOYEE WHERE DeptID = 'D02'
UNION
SELECT Name FROM EMPLOYEE WHERE Salary > 60000;
SELECT Name FROM EMPLOYEE WHERE DeptID = 'D03'
EXCEPT
SELECT Name FROM EMPLOYEE WHERE Salary > 60000;+-------------+ | Name | +-------------+ | Rohan Gupta | | Ananya Das | | Priya Nair | | Meera Iyer | +-------------+ +------------+ | Name | +------------+ | Vikram Rao | +------------+
Do not confuse UNION (adds rows from two queries) with a join (adds columns from two tables).
Key terms
- Function
- A named routine that takes input values, processes them and returns a result.
- Single-row function
- A function applied to each row separately, giving one result per row; also called a scalar function.
- Aggregate function
- A multiple-row function that returns one value for a set of rows, such as SUM() or COUNT().
- Argument
- A value passed to a function inside its brackets, such as 3 and 4 in MID(s,3,4).
- Nested function
- A function used as an argument of another function; the inner one is evaluated first.
- NULL
- A marker for a missing or unknown value; it is not zero and not an empty string.
- COUNT(*)
- Counts all rows in a table or group, including rows that contain NULLs.
- Column alias
- A temporary heading for an output column, given with AS.
- Table alias
- A short temporary name for a table, given in the FROM clause and used to qualify columns.
- GROUP BY
- Clause that collects rows with equal values in given columns into groups for aggregation.
- HAVING
- Clause that filters groups using conditions that may contain aggregate functions.
- ORDER BY
- Clause that sorts the final result in ascending (ASC) or descending (DESC) order.
- Cartesian product
- Combination of every row of one table with every row of another; rows multiply, columns add.
- Join
- An operation that combines related rows from two tables using a condition on common columns.
- Equi-join
- A join whose condition tests equality of the common column in both tables.
- Natural join
- An equi-join on all same-named columns that shows each common column only once.
- Qualified column name
- A column name written with its table name or alias, such as E.DeptID.
- Degree
- The number of columns (attributes) in a relation.
- Cardinality
- The number of rows (tuples) in a relation.
- UNION (Enrichment)
- Set operation returning rows from either of two query results, without duplicates.
MCQs
Tap an option to check it, or use Show answers above to reveal them all.
-
What is the output of
SELECT MID('INFORMATICS',3,4);?Answer(b) FORM
Counting from 1: I(1) N(2) F(3) O(4) R(5) M(6). Four characters from position 3 give FORM.
-
What does
SELECT ROUND(15.193,-1);return?Answer(d) 20
d = -1 rounds to the nearest ten. The units digit is 5, so 15.193 rounds up to 20.
-
Which of the following is a multiple-row (aggregate) function?
Answer(c) COUNT()
COUNT() returns one value for a group of rows. The others work on one value per row.
-
What is the output of
SELECT MOD(-29,4);?Answer(a) -1
29 = 4 x 7 + 1. In MySQL the remainder takes the sign of the dividend, so the result is -1.
-
What is the output of
SELECT INSTR('MISSISSIPPI','SS');?Answer(d) 3
INSTR returns the first position where SS starts. M(1) I(2) S(3) S(4), so the answer is 3.
-
Table T has 10 rows. Column Phone is NULL in 3 rows. What is
COUNT(Phone)?Answer(d) 7
COUNT(column) skips NULL values: 10 - 3 = 7. COUNT(*) would give 10.
-
What is the output of
SELECT LENGTH(TRIM(' CBSE '));?Answer(c) 4
TRIM removes the leading and trailing spaces, leaving CBSE, which has 4 characters.
-
SELECT DAYNAME('2026-01-26');returns:Answer(a) Monday
DAYNAME returns the weekday name as text. 26 January 2026 is a Monday.
-
Which clause is used to filter groups formed by GROUP BY?
Answer(b) HAVING
HAVING applies conditions to groups and may use aggregate functions; WHERE filters individual rows.
-
Which query will give an error?
Answer(c) SELECT DeptID FROM EMPLOYEE WHERE SUM(Salary)>100000;
An aggregate function such as SUM() cannot be used in WHERE. The condition belongs in HAVING with GROUP BY DeptID.
-
What is the output of
SELECT RIGHT('BENGALURU',3);?Answer(c) URU
RIGHT returns the last 3 characters: URU.
-
Relation A has 5 columns and 6 rows; relation B has 3 columns and 4 rows. The Cartesian product A x B has:
Answer(a) 8 columns and 24 rows
Degrees add (5 + 3 = 8) and cardinalities multiply (6 x 4 = 24).
-
Which function returns the month as a word, such as 'August'?
Answer(c) MONTHNAME()
MONTHNAME() returns the full month name. MONTH() returns the number 1 to 12.
-
What is the output of
SELECT POWER(2,5);?Answer(d) 32
2 raised to the power 5 is 2 x 2 x 2 x 2 x 2 = 32.
-
In an equi-join of EMPLOYEE and DEPARTMENT, why must DeptID be written as E.DeptID or D.DeptID?
Answer(d) Because both tables have a column named DeptID, so the name is ambiguous
When a column name exists in both tables, it must be qualified with the table name or alias to remove ambiguity.
-
Which is the correct order of clauses in a SELECT statement?
Answer(c) SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY
WHERE comes before GROUP BY, HAVING follows GROUP BY, and ORDER BY is always last.
-
What is the output of
SELECT ROUND(745,-2);?Answer(b) 700
Rounding to the nearest hundred: the tens digit is 4 (less than 5), so the answer is 700.
-
AVG(Bonus)is calculated on a column with values 4000, NULL, 6000. The result is:Answer(a) 5000
NULL is ignored. (4000 + 6000) / 2 = 5000.
-
What is the output of
SELECT SUBSTR('KASHMIR',-3);?Answer(c) MIR
A negative position counts from the right. Starting 3 characters from the end and taking the rest gives MIR.
-
Which statement about single-row functions is TRUE?
Answer(b) They return one result for each row processed
Single-row (scalar) functions return a value for every row and can appear in SELECT, WHERE and ORDER BY.
-
What is the output of
SELECT UCASE(MID('india gate',7));?Answer(a) GATE
Position 7 of 'india gate' is g (the space is position 6). MID returns gate, and UCASE converts it to GATE.
-
Which query lists departments having more than 2 employees?
Answer(b) SELECT DeptID FROM EMPLOYEE GROUP BY DeptID HAVING COUNT(*) > 2;
Rows must first be grouped by DeptID, then HAVING COUNT(*) > 2 keeps groups with more than two rows.
-
What is the output of
SELECT MID('PRACTICES', INSTR('PRACTICES','C'), 3);?Answer(a) CTI
The inner INSTR finds the first C at position 4. MID('PRACTICES',4,3) returns CTI.
-
Which keyword sorts the result from highest to lowest?
Answer(a) DESC
DESC sorts in descending order. ASC is the default ascending order.
-
(Enrichment) Which set operation returns only the rows that appear in the results of both queries?
Answer(c) INTERSECT
INTERSECT returns the common rows. UNION returns rows from either query; MINUS (EXCEPT in MySQL) returns rows of the first not in the second.
Assertion–Reason
Assertion (A):
SELECT COUNT(Bonus) FROM EMPLOYEE;may return a smaller number thanSELECT COUNT(*) FROM EMPLOYEE;.Reason (R): COUNT(column) ignores NULL values, whereas COUNT(*) counts every row.
Answer(A)
Both are true and the reason directly explains why the counts can differ.
Assertion (A): The condition
AVG(Marks) > 60cannot be written in a WHERE clause.Reason (R): WHERE is applied to individual rows before any groups are formed.
Answer(A)
Because WHERE works row by row before grouping, aggregate values do not exist yet; such conditions go in HAVING.
Assertion (A):
SELECT ROUND(15.193,-1);returns 15.2.Reason (R): A negative second argument in ROUND() rounds the number to the left of the decimal point.
Answer(D)
The assertion is false: the answer is 20. The reason is true: d = -1 rounds to the nearest ten.
Assertion (A):
INSTR('CBSE','X')returns 0.Reason (R): MySQL string positions start from 0.
Answer(C)
INSTR does return 0 when the substring is missing, but positions in MySQL start from 1, so R is false.
Assertion (A): An equi-join of two tables usually returns fewer rows than their Cartesian product.
Reason (R): The Cartesian product has as many columns as the sum of the columns of both tables.
Answer(B)
Both statements are true, but the number of columns does not explain why the join has fewer rows. The join keeps only rows where the common column matches.
Assertion (A):
UPPER()andUCASE()give the same result.Reason (R): MySQL provides some functions under more than one name.
Answer(A)
UCASE is a synonym of UPPER, just as LCASE/LOWER and MID/SUBSTRING/SUBSTR are synonyms.
Short answer
- 2 marks
Differentiate between single-row functions and aggregate functions. Give one example of each.
AnswerA single-row function works on one value of each row and returns one result per row, for example
UPPER(Name).An aggregate function works on a group of rows and returns a single result for the group, for example
SUM(Salary). - 2 marks
Write the output of:
SELECT ROUND(1567.89,-2);SELECT MOD(29,4);
Answer- 1600 (rounded to the nearest hundred)
- 1 (29 = 4 x 7 + 1)
- 2 marks
Write the output of:
SELECT LEFT('BENGALURU',4);SELECT LENGTH('IP 065');
Answer- BENG
- 6 (the space is counted)
- 2 marks
Differentiate between
COUNT(*)andCOUNT(column_name)with an example.AnswerCOUNT(*)counts all rows, including rows with NULL values.COUNT(column_name)counts only the non-NULL values of that column.In EMPLOYEE,
COUNT(*)is 8 butCOUNT(Bonus)is 5, because Bonus is NULL for three employees. - 2 marks
Differentiate between WHERE and HAVING clauses.
Answer- WHERE filters individual rows before grouping and cannot contain aggregate functions, e.g.
WHERE Salary > 50000. - HAVING filters groups after
GROUP BYand can contain aggregate functions, e.g.HAVING COUNT(*) > 2.
- WHERE filters individual rows before grouping and cannot contain aggregate functions, e.g.
- 2 marks
Write the output of:
SELECT MONTHNAME('2023-10-02');SELECT DAY('2024-02-29');
Answer- October
- 29
- 2 marks
What is a Cartesian product? Table STUDENT has 4 columns and 30 rows; table HOUSE has 3 columns and 4 rows. Find the degree and cardinality of STUDENT x HOUSE.
AnswerA Cartesian product pairs every row of one table with every row of another.
- Degree = 4 + 3 = 7
- Cardinality = 30 x 4 = 120
- 2 marks
What is an equi-join? Why are table aliases used in joins?
AnswerAn equi-join combines two tables and keeps only those rows where the common column has equal values, using
=in the join condition.Table aliases are short names (such as E for EMPLOYEE) that make queries shorter and are used to qualify columns that exist in both tables.
- 2 marks
Write the output of:
SELECT INSTR('BANANA','NA');SELECT SUBSTRING('INFORMATICS',6);
Answer- 3
- MATICS
- 2 marks
Rahul wrote:
SELECT Name, SUM(Salary) FROM EMPLOYEE;and got an error. Explain the problem and write a corrected query that shows each department's total salary.AnswerName has one value per row, but SUM(Salary) produces one value for all rows, so they cannot be shown together without grouping. A plain column with an aggregate must appear in GROUP BY.
MySQL SELECT DeptID, SUM(Salary) FROM EMPLOYEE GROUP BY DeptID ORDER BY DeptID;Output+--------+-------------+ | DeptID | SUM(Salary) | +--------+-------------+ | D01 | 132350 | | D02 | 95300 | | D03 | 191700 | +--------+-------------+
- 2 marks
Name the functions used to (a) remove spaces only from the right side of a string, and (b) find the weekday name of a date.
Answer(a)
RTRIM()(b)
DAYNAME() - 2 marks
Write the output of:
SELECT UCASE(LEFT('delhi',1));SELECT ROUND(-3.45,1);
Answer- D
- -3.5 (a halfway value is rounded away from zero)
- 2 marks
Write a query to display the name of each employee and the year in which they joined, for employees who joined after 2017, sorted by year of joining.
AnswerUsing the OFFICE database:
MySQL SELECT Name, YEAR(DOJ) AS JoinYear FROM EMPLOYEE WHERE YEAR(DOJ) > 2017 ORDER BY JoinYear;Output+-------------+----------+ | Name | JoinYear | +-------------+----------+ | Priya Nair | 2018 | | Kabir Singh | 2019 | | Meera Iyer | 2020 | | Vikram Rao | 2021 | +-------------+----------+
- 2 marks
Why does
SELECT AVG(Bonus) FROM EMPLOYEE;give 5300.0000 whileSELECT SUM(Bonus)/COUNT(*) FROM EMPLOYEE;gives 3312.5000?AnswerAVG() ignores NULLs, so it divides the total 26500 by the 5 non-NULL bonuses. COUNT(*) counts all 8 rows, so the second expression divides 26500 by 8.
Long answer
- 3 marks
Consider the EMPLOYEE table of the OFFICE database. Write SQL queries for the following:
- Display the name and salary rounded to the nearest thousand.
- Display the first name of every employee.
- Display names of employees who joined in a month whose name is 'May' or 'March'.
AnswerROUND(Salary,-3)rounds to thousands.- The first name is everything before the space.
MONTHNAME()returns text, so compare with words.
MySQL SELECT Name, ROUND(Salary,-3) FROM EMPLOYEE WHERE DeptID = 'D01'; SELECT LEFT(Name, INSTR(Name,' ') - 1) AS FirstName FROM EMPLOYEE WHERE DeptID = 'D02'; SELECT Name FROM EMPLOYEE WHERE MONTHNAME(DOJ) IN ('May','March');Output+--------------+------------------+ | Name | ROUND(Salary,-3) | +--------------+------------------+ | Aarav Sharma | 52000 | | Kabir Singh | 39000 | | Sneha Patil | 41000 | +--------------+------------------+ +-----------+ | FirstName | +-----------+ | Rohan | | Ananya | +-----------+ +--------------+ | Name | +--------------+ | Aarav Sharma | | Ananya Das | +--------------+
- 3 marks
Write the output of the following queries:
SELECT POWER(4,0.5), MOD(10,0);SELECT RIGHT(LEFT('INFORMATICS',6),3);SELECT LENGTH(LTRIM(' Goa ')), LENGTH(RTRIM(' Goa '));
Answer- POWER(4,0.5) is the square root of 4, which is 2. MOD by zero gives NULL.
- LEFT gives INFORM; the last 3 characters of INFORM are ORM.
- ' Goa ' has 7 characters. Removing 2 leading spaces leaves 5; removing 2 trailing spaces also leaves 5.
MySQL SELECT POWER(4,0.5), MOD(10,0); SELECT RIGHT(LEFT('INFORMATICS',6),3); SELECT LENGTH(LTRIM(' Goa ')), LENGTH(RTRIM(' Goa '));Output+--------------+-----------+ | POWER(4,0.5) | MOD(10,0) | +--------------+-----------+ | 2 | NULL | +--------------+-----------+ +--------------------------------+ | RIGHT(LEFT('INFORMATICS',6),3) | +--------------------------------+ | ORM | +--------------------------------+ +--------------------------+--------------------------+ | LENGTH(LTRIM(' Goa ')) | LENGTH(RTRIM(' Goa ')) | +--------------------------+--------------------------+ | 5 | 5 | +--------------------------+--------------------------+ - 3 marks
Using the EMPLOYEE table, write queries to:
- Display each department's DeptID and the difference between its highest and lowest salary, largest difference first.
- Display the number of male and female employees.
- Display DeptIDs whose average salary is more than 50000.
AnswerEach query needs GROUP BY; the third also needs HAVING because the condition uses an aggregate.
MySQL SELECT DeptID, MAX(Salary) - MIN(Salary) AS Gap FROM EMPLOYEE GROUP BY DeptID ORDER BY Gap DESC; SELECT Gender, COUNT(*) FROM EMPLOYEE GROUP BY Gender ORDER BY Gender; SELECT DeptID FROM EMPLOYEE GROUP BY DeptID HAVING AVG(Salary) > 50000;Output+--------+-------+ | DeptID | Gap | +--------+-------+ | D03 | 14500 | | D01 | 13600 | | D02 | 3700 | +--------+-------+ +--------+----------+ | Gender | COUNT(*) | +--------+----------+ | F | 4 | | M | 4 | +--------+----------+ +--------+ | DeptID | +--------+ | D03 | +--------+
- 5 marks
Explain with examples the use of GROUP BY, HAVING and ORDER BY in one query. Describe the order in which MySQL processes a query that contains WHERE, GROUP BY, HAVING and ORDER BY.
AnswerGROUP BY forms groups of rows with the same value; HAVING keeps only the groups that satisfy a condition; ORDER BY sorts the final output.
Processing order: FROM, then WHERE (rows filtered), then GROUP BY (groups formed), then HAVING (groups filtered), then SELECT (output columns computed), and finally ORDER BY (rows sorted).
In the query below, WHERE keeps employees who joined before 2020, GROUP BY makes one group per department, HAVING keeps departments whose salary bill is over 90000, and ORDER BY sorts by the bill.
MySQL SELECT DeptID, SUM(Salary) AS Bill FROM EMPLOYEE WHERE YEAR(DOJ) < 2020 GROUP BY DeptID HAVING SUM(Salary) > 90000 ORDER BY Bill DESC;Output+--------+--------+ | DeptID | Bill | +--------+--------+ | D01 | 132350 | | D02 | 95300 | +--------+--------+
- 5 marks
Write SQL queries on the OFFICE database (EMPLOYEE and DEPARTMENT) for the following. Use table aliases.
- Display employee name, department name and city for all employees, using the WHERE form of equi-join.
- Repeat part 1 using JOIN ... ON.
- Display the city and number of employees working in each city.
- Display names of employees who work in Bengaluru and earn more than 60000.
- Display the name of each department and the total bonus paid in it.
AnswerParts 1 and 2 produce the same 8 rows; only part 2's output is shown. In part 5, SUM() skips the NULL bonuses.
MySQL SELECT E.Name, D.DeptName, D.City FROM EMPLOYEE E, DEPARTMENT D WHERE E.DeptID = D.DeptID; SELECT E.Name, D.DeptName, D.City FROM EMPLOYEE E JOIN DEPARTMENT D ON E.DeptID = D.DeptID ORDER BY E.Name; SELECT D.City, COUNT(*) FROM EMPLOYEE E, DEPARTMENT D WHERE E.DeptID = D.DeptID GROUP BY D.City ORDER BY D.City; SELECT E.Name FROM EMPLOYEE E, DEPARTMENT D WHERE E.DeptID = D.DeptID AND D.City = 'Bengaluru' AND E.Salary > 60000; SELECT D.DeptName, SUM(E.Bonus) FROM EMPLOYEE E JOIN DEPARTMENT D ON E.DeptID = D.DeptID GROUP BY D.DeptName ORDER BY D.DeptName;Output+--------------+----------+-----------+ | Name | DeptName | City | +--------------+----------+-----------+ | Aarav Sharma | Sales | Mumbai | | Ananya Das | Accounts | Delhi | | Kabir Singh | Sales | Mumbai | | Meera Iyer | IT | Bengaluru | | Priya Nair | IT | Bengaluru | | Rohan Gupta | Accounts | Delhi | | Sneha Patil | Sales | Mumbai | | Vikram Rao | IT | Bengaluru | +--------------+----------+-----------+ +-----------+----------+ | City | COUNT(*) | +-----------+----------+ | Bengaluru | 3 | | Delhi | 2 | | Mumbai | 3 | +-----------+----------+ +------------+ | Name | +------------+ | Priya Nair | | Meera Iyer | +------------+ +----------+--------------+ | DeptName | SUM(E.Bonus) | +----------+--------------+ | Accounts | 7500 | | IT | 14000 | | Sales | 5000 | +----------+--------------+
- 5 marks
Explain any three text functions and any two date functions of MySQL with syntax and one example each.
AnswerText functions:
UPPER(s)/UCASE(s): converts s to capital letters.UPPER('goa')gives GOA.MID(s,p,n)/SUBSTRING()/SUBSTR(): returns n characters of s from position p.MID('COMPUTER',4,3)gives PUT.INSTR(s,sub): returns the position of the first occurrence of sub in s, or 0.INSTR('PRACTICES','C')gives 4.
Date functions:
MONTHNAME(d): returns the month name.MONTHNAME('2025-08-15')gives August.DAYNAME(d): returns the weekday name.DAYNAME('2025-08-15')gives Friday.
- 3 marks
A table SALES(BillNo, Item, Qty, Rate, BillDate) stores sales of a school canteen. Write queries to:
- Display the total quantity sold for each item.
- Display items whose total quantity sold is at least 50.
- Display the number of bills raised in each month, showing the month name.
AnswerThe answers use GROUP BY on a column and on a function of a column.
MySQL SELECT Item, SUM(Qty) FROM SALES GROUP BY Item; SELECT Item, SUM(Qty) FROM SALES GROUP BY Item HAVING SUM(Qty) >= 50; SELECT MONTHNAME(BillDate), COUNT(*) FROM SALES GROUP BY MONTH(BillDate), MONTHNAME(BillDate) ORDER BY MONTH(BillDate); - 3 marks
Differentiate between: (a) ROUND(n) and ROUND(n,-2), (b) LTRIM() and TRIM(), (c) MONTH() and MONTHNAME(). Give one example of each.
Answer(a)
ROUND(n)rounds to the nearest whole number:ROUND(1567.89)is 1568.ROUND(n,-2)rounds to the nearest hundred:ROUND(1567.89,-2)is 1600.(b)
LTRIM()removes only leading spaces:LENGTH(LTRIM(' Goa '))is 5.TRIM()removes leading and trailing spaces:LENGTH(TRIM(' Goa '))is 3.(c)
MONTH()returns a number:MONTH('2025-08-15')is 8.MONTHNAME()returns text:MONTHNAME('2025-08-15')is August.
Case-based
Sunrise Public School, Jaipur, keeps fee data in a table FEES(AdmNo, SName, Class, Month, Amount, PayDate). PayDate is NULL when a student has not yet paid that month's fee. The accountant, Mrs. Kapoor, needs some reports.
- 1 mark
Write a query to display the total fee collected for each class.
AnswerSELECT Class, SUM(Amount) FROM FEES WHERE PayDate IS NOT NULL GROUP BY Class; - 1 mark
Write a query to count how many fee entries are still unpaid.
AnswerSELECT COUNT(*) FROM FEES WHERE PayDate IS NULL; - 1 mark
Mrs. Kapoor runs
SELECT COUNT(PayDate) FROM FEES;andSELECT COUNT(*) FROM FEES;and gets different numbers. Explain why.AnswerCOUNT(PayDate) counts only non-NULL dates (paid entries), while COUNT(*) counts every row, including unpaid ones.
- 2 marks
Write a query to show classes where more than 10 payments were made on a Saturday.
AnswerSELECT Class FROM FEES WHERE DAYNAME(PayDate) = 'Saturday' GROUP BY Class HAVING COUNT(*) > 10;
A cricket academy in Chennai stores data in two tables:
PLAYER(PID, PName, Role, TeamID, Runs)TEAM(TeamID, TName, Coach)
TeamID is common to both tables. The academy has 20 players and 4 teams.
- 1 mark
What will be the degree and cardinality of
SELECT * FROM PLAYER, TEAM;?AnswerDegree = 5 + 3 = 8; cardinality = 20 x 4 = 80.
- 1 mark
Write a query to show each player's name with the name of their team (equi-join with aliases).
AnswerSELECT P.PName, T.TName FROM PLAYER P, TEAM T WHERE P.TeamID = T.TeamID; - 2 marks
Write a query to display each team name with the total runs scored by its players, highest first.
AnswerSELECT T.TName, SUM(P.Runs) AS Total FROM PLAYER P JOIN TEAM T ON P.TeamID = T.TeamID GROUP BY T.TName ORDER BY Total DESC; - 1 mark
Write a query to display the names of players in uppercase whose names have more than 6 characters.
AnswerSELECT UPPER(PName) FROM PLAYER WHERE LENGTH(PName) > 6;
An online bookstore in Kolkata has a table ORDERS(OrderID, CustName, Email, OrderDate, Amount). The manager wants to clean and analyse the data. Some customer names were typed with extra spaces at the start and end.
- 1 mark
Write a query to display customer names without leading and trailing spaces.
AnswerSELECT TRIM(CustName) FROM ORDERS; - 1 mark
Write a query to display the part of each e-mail ID before the @ symbol.
AnswerSELECT LEFT(Email, INSTR(Email,'@') - 1) FROM ORDERS; - 2 marks
Write a query to display the month name and total amount of orders for each month of the year 2025.
AnswerSELECT MONTHNAME(OrderDate), SUM(Amount) FROM ORDERS WHERE YEAR(OrderDate) = 2025 GROUP BY MONTH(OrderDate), MONTHNAME(OrderDate) ORDER BY MONTH(OrderDate); - 1 mark
Write a query to display each amount rounded to the nearest 10 rupees.
AnswerSELECT OrderID, ROUND(Amount,-1) FROM ORDERS;
Practicals
1Create database and STUDENT table
Create a database SCHOOL. In it, create a table STUDENT with columns StudentID (integer, primary key), Name, Class, Gender, DOB, Marks and HouseID. Display the structure of the table.
CREATE DATABASE SCHOOL;
USE SCHOOL;
CREATE TABLE STUDENT (
StudentID INT PRIMARY KEY,
Name VARCHAR(30) NOT NULL,
Class CHAR(3),
Gender CHAR(1),
DOB DATE,
Marks DECIMAL(5,1),
HouseID CHAR(2)
);
DESC STUDENT;+-----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+-------+ | StudentID | int | NO | PRI | NULL | | | Name | varchar(30) | NO | | NULL | | | Class | char(3) | YES | | NULL | | | Gender | char(1) | YES | | NULL | | | DOB | date | YES | | NULL | | | Marks | decimal(5,1) | YES | | NULL | | | HouseID | char(2) | YES | | NULL | | +-----------+--------------+------+-----+---------+-------+
Viva questions (3)
- What does PRIMARY KEY ensure? Values in the column are unique and never NULL.
- Why is Marks declared DECIMAL(5,1)? It allows up to 5 digits with 1 digit after the decimal point, e.g. 88.5.
- Which command shows the structure of a table? DESC or DESCRIBE.
2Insert and display records
Insert the details of 10 students into STUDENT and display the entire table.
INSERT INTO STUDENT VALUES
(1201, 'Ishaan Verma', 'XII', 'M', '2008-04-14', 88.5, 'H1'),
(1202, 'Diya Menon', 'XII', 'F', '2008-09-02', 92.0, 'H2'),
(1203, 'Arjun Reddy', 'XII', 'M', '2007-12-21', 67.0, 'H3'),
(1204, 'Kavya Joshi', 'XII', 'F', '2008-01-30', 79.5, 'H1'),
(1205, 'Mohammed Faiz', 'XII', 'M', '2008-06-11', 54.0, 'H2'),
(1206, 'Tanvi Kulkarni', 'XII', 'F', '2008-09-25', 81.0, 'H3'),
(1207, 'Harpreet Kaur', 'XII', 'F', '2007-11-08', 73.5, 'H1'),
(1208, 'Siddharth Bose', 'XII', 'M', '2008-03-17', 95.5, 'H2'),
(1209, 'Nikhil Yadav', 'XII', 'M', '2008-07-04', 48.0, 'H3'),
(1210, 'Riya Thomas', 'XII', 'F', '2008-02-12', 86.0, 'H1');
SELECT * FROM STUDENT;+-----------+----------------+-------+--------+------------+-------+---------+ | StudentID | Name | Class | Gender | DOB | Marks | HouseID | +-----------+----------------+-------+--------+------------+-------+---------+ | 1201 | Ishaan Verma | XII | M | 2008-04-14 | 88.5 | H1 | | 1202 | Diya Menon | XII | F | 2008-09-02 | 92.0 | H2 | | 1203 | Arjun Reddy | XII | M | 2007-12-21 | 67.0 | H3 | | 1204 | Kavya Joshi | XII | F | 2008-01-30 | 79.5 | H1 | | 1205 | Mohammed Faiz | XII | M | 2008-06-11 | 54.0 | H2 | | 1206 | Tanvi Kulkarni | XII | F | 2008-09-25 | 81.0 | H3 | | 1207 | Harpreet Kaur | XII | F | 2007-11-08 | 73.5 | H1 | | 1208 | Siddharth Bose | XII | M | 2008-03-17 | 95.5 | H2 | | 1209 | Nikhil Yadav | XII | M | 2008-07-04 | 48.0 | H3 | | 1210 | Riya Thomas | XII | F | 2008-02-12 | 86.0 | H1 | +-----------+----------------+-------+--------+------------+-------+---------+
Viva questions (3)
- In what format are dates entered in MySQL? 'YYYY-MM-DD' within quotes.
- What happens if two rows have the same StudentID? The second INSERT fails with a duplicate primary key error.
- How do you display all columns? Use SELECT * FROM table_name.
3Insert a new student and delete a student
Insert the details of a new student (StudentID 1211) giving the column names explicitly. Then delete the student with StudentID 1209. Display the affected part of the table.
INSERT INTO STUDENT (StudentID, Name, Class, Gender, DOB, Marks, HouseID)
VALUES (1211, 'Aditi Saxena', 'XII', 'F', '2008-05-19', 77.0, 'H2');
DELETE FROM STUDENT WHERE StudentID = 1209;
SELECT StudentID, Name, Marks FROM STUDENT WHERE StudentID >= 1208;+-----------+----------------+-------+ | StudentID | Name | Marks | +-----------+----------------+-------+ | 1208 | Siddharth Bose | 95.5 | | 1210 | Riya Thomas | 86.0 | | 1211 | Aditi Saxena | 77.0 | +-----------+----------------+-------+
Viva questions (3)
- What happens if DELETE is given without WHERE? All rows of the table are deleted.
- Why list column names in INSERT? The values can be given in any order, and unlisted columns get NULL or their default.
- Is DELETE a DDL or DML command? DML.
4Students scoring more than 80
Display StudentID, Name and Marks of students who scored more than 80 marks.
SELECT StudentID, Name, Marks FROM STUDENT
WHERE Marks > 80;+-----------+----------------+-------+ | StudentID | Name | Marks | +-----------+----------------+-------+ | 1201 | Ishaan Verma | 88.5 | | 1202 | Diya Menon | 92.0 | | 1206 | Tanvi Kulkarni | 81.0 | | 1208 | Siddharth Bose | 95.5 | | 1210 | Riya Thomas | 86.0 | +-----------+----------------+-------+
Viva questions (2)
- Would
Marks >= 80change the result here? No, because no student has exactly 80. - Which clause filters rows? WHERE.
5MIN, MAX, SUM and AVG of marks
Find the minimum, maximum, total and average marks of all students. Then show the same statistics (without SUM) separately for boys and girls.
SELECT MIN(Marks), MAX(Marks), SUM(Marks), ROUND(AVG(Marks),2) AS Average
FROM STUDENT;
SELECT Gender, MIN(Marks), MAX(Marks), ROUND(AVG(Marks),1) AS Average
FROM STUDENT
GROUP BY Gender
ORDER BY Gender;+------------+------------+------------+---------+ | MIN(Marks) | MAX(Marks) | SUM(Marks) | Average | +------------+------------+------------+---------+ | 54.0 | 95.5 | 794.0 | 79.40 | +------------+------------+------------+---------+ +--------+------------+------------+---------+ | Gender | MIN(Marks) | MAX(Marks) | Average | +--------+------------+------------+---------+ | F | 73.5 | 92.0 | 81.5 | | M | 54.0 | 95.5 | 76.3 | +--------+------------+------------+---------+
Viva questions (3)
- Why is ROUND() used with AVG()? To limit the decimal places in the output.
- Do aggregate functions count NULL marks? No, they ignore NULL values.
- How many rows does the second query return, and why? Two, one for each value of Gender.
6Customers from each country (GROUP BY)
Create a table CUSTOMER(CustID, CustName, Country), insert some records, and display the total number of customers from each country. Also list only countries with at least 2 customers.
CREATE TABLE CUSTOMER (
CustID INT PRIMARY KEY,
CustName VARCHAR(30),
Country VARCHAR(20)
);
INSERT INTO CUSTOMER VALUES
(1, 'Anil Mehta', 'India'),
(2, 'Fatima Noor', 'UAE'),
(3, 'Ramesh Pillai', 'India'),
(4, 'Tenzing Sherpa','Nepal'),
(5, 'Sunita Rao', 'India'),
(6, 'Omar Khalid', 'UAE'),
(7, 'Pema Wangchuk', 'Bhutan'),
(8, 'Bikash Thapa', 'Nepal'),
(9, 'Lakshmi Iyer', 'India');
SELECT Country, COUNT(*) AS Customers
FROM CUSTOMER
GROUP BY Country
ORDER BY Customers DESC, Country;
SELECT Country, COUNT(*) AS Customers
FROM CUSTOMER
GROUP BY Country
HAVING COUNT(*) >= 2
ORDER BY Country;+---------+-----------+ | Country | Customers | +---------+-----------+ | India | 4 | | Nepal | 2 | | UAE | 2 | | Bhutan | 1 | +---------+-----------+ +---------+-----------+ | Country | Customers | +---------+-----------+ | India | 4 | | Nepal | 2 | | UAE | 2 | +---------+-----------+
Viva questions (2)
- Why HAVING and not WHERE for
COUNT(*) >= 2? The condition uses an aggregate, which is allowed only in HAVING. - What decides the order of groups in the output? Only ORDER BY; without it the order is not guaranteed.
7Order by marks (descending)
Display StudentID and Marks of all students in descending order of marks.
SELECT StudentID, Marks FROM STUDENT
ORDER BY Marks DESC;+-----------+-------+ | StudentID | Marks | +-----------+-------+ | 1208 | 95.5 | | 1202 | 92.0 | | 1201 | 88.5 | | 1210 | 86.0 | | 1206 | 81.0 | | 1204 | 79.5 | | 1211 | 77.0 | | 1207 | 73.5 | | 1203 | 67.0 | | 1205 | 54.0 | +-----------+-------+
Viva questions (2)
- What is the default sort order? Ascending (ASC).
- Where is ORDER BY written in a query? At the end, after WHERE, GROUP BY and HAVING.
8Text functions on student names
For students of house H1, display the name in capitals, the first three letters as a code, the length of the name, and the surname (text after the space). Also list names ending with the letter 'a'.
SELECT UPPER(Name) AS NameCaps,
LEFT(Name, 3) AS Code,
LENGTH(Name) AS Len,
MID(Name, INSTR(Name,' ') + 1) AS Surname
FROM STUDENT
WHERE HouseID = 'H1';
SELECT Name FROM STUDENT WHERE RIGHT(Name, 1) = 'a';+---------------+------+-----+---------+ | NameCaps | Code | Len | Surname | +---------------+------+-----+---------+ | ISHAAN VERMA | Ish | 12 | Verma | | KAVYA JOSHI | Kav | 11 | Joshi | | HARPREET KAUR | Har | 13 | Kaur | | RIYA THOMAS | Riy | 11 | Thomas | +---------------+------+-----+---------+ +--------------+ | Name | +--------------+ | Ishaan Verma | | Aditi Saxena | +--------------+
Viva questions (3)
- What does INSTR() return if the space is missing? 0.
- Why is 1 added to INSTR(Name,' ') for the surname? The surname begins one position after the space.
- Is the comparison RIGHT(Name,1) = 'a' case-sensitive in MySQL by default? No, the default collation ignores case.
9Date functions on date of birth
Display name, DOB, day, month name, year and weekday of birth for students born from January to April 2008, in order of DOB. Then show the months in which more than one student was born.
SELECT Name, DOB, DAY(DOB) AS D, MONTHNAME(DOB) AS Mon,
YEAR(DOB) AS Yr, DAYNAME(DOB) AS BornOn
FROM STUDENT
WHERE YEAR(DOB) = 2008 AND MONTH(DOB) <= 4
ORDER BY DOB;
SELECT MONTHNAME(DOB) AS Mon, COUNT(*) FROM STUDENT
GROUP BY MONTH(DOB), MONTHNAME(DOB)
HAVING COUNT(*) > 1;+----------------+------------+------+----------+------+-----------+ | Name | DOB | D | Mon | Yr | BornOn | +----------------+------------+------+----------+------+-----------+ | Kavya Joshi | 2008-01-30 | 30 | January | 2008 | Wednesday | | Riya Thomas | 2008-02-12 | 12 | February | 2008 | Tuesday | | Siddharth Bose | 2008-03-17 | 17 | March | 2008 | Monday | | Ishaan Verma | 2008-04-14 | 14 | April | 2008 | Monday | +----------------+------------+------+----------+------+-----------+ +-----------+----------+ | Mon | COUNT(*) | +-----------+----------+ | September | 2 | +-----------+----------+
Viva questions (3)
- Which function returns the weekday name? DAYNAME().
- What type of value does MONTH() return? A number from 1 to 12.
- Why group by both MONTH(DOB) and MONTHNAME(DOB)? Every non-aggregated column in SELECT must be in GROUP BY; MONTH keeps the grouping correct.
10Equi-join STUDENT and HOUSE
Create a table HOUSE(HouseID, HouseName, Incharge). Display student name, house name and house in-charge for students with marks 85 or more (WHERE form of equi-join). Then, using JOIN ... ON, show each house's member count and average marks, only for houses averaging above 75.
CREATE TABLE HOUSE (
HouseID CHAR(2) PRIMARY KEY,
HouseName VARCHAR(15),
Incharge VARCHAR(25)
);
INSERT INTO HOUSE VALUES
('H1', 'Shivaji', 'Mr. Deshpande'),
('H2', 'Tagore', 'Ms. Banerjee'),
('H3', 'Raman', 'Mr. Krishnan'),
('H4', 'Kalpana', 'Ms. Chawla');
SELECT S.Name, H.HouseName, H.Incharge
FROM STUDENT S, HOUSE H
WHERE S.HouseID = H.HouseID AND S.Marks >= 85
ORDER BY S.Name;
SELECT H.HouseName, COUNT(*) AS Members, ROUND(AVG(S.Marks),1) AS AvgMarks
FROM STUDENT S JOIN HOUSE H ON S.HouseID = H.HouseID
GROUP BY H.HouseName
HAVING AVG(S.Marks) > 75
ORDER BY AvgMarks DESC;+----------------+-----------+---------------+ | Name | HouseName | Incharge | +----------------+-----------+---------------+ | Diya Menon | Tagore | Ms. Banerjee | | Ishaan Verma | Shivaji | Mr. Deshpande | | Riya Thomas | Shivaji | Mr. Deshpande | | Siddharth Bose | Tagore | Ms. Banerjee | +----------------+-----------+---------------+ +-----------+---------+----------+ | HouseName | Members | AvgMarks | +-----------+---------+----------+ | Shivaji | 4 | 81.9 | | Tagore | 4 | 79.6 | +-----------+---------+----------+
Viva questions (3)
- Why does house H4 (Kalpana) not appear? No student has HouseID H4, and an equi-join shows only matching rows.
- How many rows would STUDENT x HOUSE have? 10 x 4 = 40.
- What are S and H in the query? Table aliases for STUDENT and HOUSE.
Common mistakes
Using an aggregate in WHERE, as in
WHERE AVG(Salary) > 50000. Aggregates are not known while rows are being filtered; move the condition toHAVINGafterGROUP BY.Counting string positions from 0. MySQL positions start at 1, so
MID('INFORMATICS',3,4)is FORM, not ORMA. Number the letters before answering.Treating NULL as 0.
COUNT(Bonus),SUM(Bonus)andAVG(Bonus)all skip NULLs, soAVG(Bonus)divides by 5, not 8. UseCOUNT(*)to count every row.Selecting a non-grouped column with an aggregate, such as
SELECT Name, MAX(Salary) FROM EMPLOYEE GROUP BY DeptID. Every plain column in SELECT must appear in GROUP BY.Getting negative ROUND() wrong, for example writing
ROUND(15.193,-1)as 15.2 or 10. A negative d rounds to tens, hundreds and so on; the answer here is 20.Expecting
INSTR()to return -1 or NULL when the substring is missing. It returns 0.Writing an unqualified common column in a join (
SELECT DeptID FROM EMPLOYEE, DEPARTMENT ...). MySQL reports that DeptID is ambiguous; writeE.DeptIDorD.DeptID.Forgetting the join condition, which silently produces a Cartesian product with 8 x 4 = 32 rows instead of 8 matched rows.
Writing clauses in the wrong order, such as
ORDER BYbeforeGROUP BY, orHAVINGbeforeGROUP BY. The order is SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY.Thinking
TRIM()removes all spaces. It removes only leading and trailing spaces; the space between first and last names stays.