Chapter 16 Intermediate 60 Questions

Practice Questions — Date and Time Functions

← Back to Notes
13 Easy
18 Medium
9 Hard

Topic-Specific Questions

Question 1
Easy
What does this query return (assume today is 2026-04-16)?
SELECT CURDATE();
CURDATE() returns only the date portion.
2026-04-16
Question 2
Easy
What is the output?
SELECT DATEDIFF('2026-04-16', '2026-04-10');
DATEDIFF(a, b) = a - b in days.
6
Question 3
Easy
What is the output?
SELECT DATEDIFF('2026-04-10', '2026-04-16');
DATEDIFF can return negative values.
-6
Question 4
Easy
What is the output?
SELECT DATE_ADD('2026-04-16', INTERVAL 7 DAY);
Add 7 days to April 16.
2026-04-23
Question 5
Easy
What is the output?
SELECT DATE_SUB('2026-04-16', INTERVAL 1 MONTH);
Subtract one month from April 16.
2026-03-16
Question 6
Easy
What is the output?
SELECT YEAR('2026-04-16'), MONTH('2026-04-16'), DAY('2026-04-16');
Each function extracts a single part.
2026 4 16
Question 7
Easy
What is the output?
SELECT DATE_FORMAT('2026-04-16', '%d-%m-%Y');
%d = day, %m = month, %Y = 4-digit year.
16-04-2026
Question 8
Easy
What is the output?
SELECT DAYNAME('2026-04-16');
April 16, 2026 falls on which day?
Thursday
Question 9
Easy
What is the output?
SELECT LAST_DAY('2026-02-10');
2026 is not a leap year.
2026-02-28
Question 10
Easy
What is the output?
SELECT LAST_DAY('2028-02-10');
Is 2028 a leap year?
2028-02-29
Question 11
Medium
What is the output?
SELECT TIMESTAMPDIFF(MONTH, '2024-01-15', '2026-04-16');
Count whole months between the two dates.
27
Question 12
Medium
What is the output?
SELECT TIMESTAMPDIFF(YEAR, '2010-04-17', '2026-04-16');
The second date is ONE DAY before the birthday.
15
Question 13
Medium
What is the output?
SELECT DATE_ADD('2026-01-31', INTERVAL 1 MONTH);
January 31 + 1 month. What is February's last day?
2026-02-28
Question 14
Medium
What is the output?
SELECT QUARTER('2026-04-16'), QUARTER('2026-11-05');
Quarters are Jan-Mar=1, Apr-Jun=2, Jul-Sep=3, Oct-Dec=4.
2 4
Question 15
Medium
What is the output?
SELECT DAYOFWEEK('2026-04-16'), WEEKDAY('2026-04-16');
DAYOFWEEK: Sunday=1. WEEKDAY: Monday=0.
5 3
Question 16
Medium
What is the output?
SELECT STR_TO_DATE('16/04/2026', '%d/%m/%Y');
Parse the string using the given format.
2026-04-16
Question 17
Medium
What is the output?
SELECT STR_TO_DATE('2026-13-01', '%Y-%m-%d');
Is month 13 valid?
NULL
Question 18
Hard
What is the output?
SELECT DATE_FORMAT('2026-04-16 14:23:07', '%W, %d %b %Y %h:%i %p');
%W full day, %b short month, %h 12-hour, %p AM/PM.
Thursday, 16 Apr 2026 02:23 PM
Question 19
Hard
What is the output?
SELECT DATE_ADD(LAST_DAY('2026-02-05'), INTERVAL 1 DAY);
LAST_DAY of Feb 2026, then add 1.
2026-03-01
Question 20
Medium
When should you use DATE vs DATETIME vs TIMESTAMP?
Think about time zones and what the column represents.
Use DATE when only the calendar day matters (date of birth, invoice date, holiday). Use DATETIME for wall-clock moments that should not shift with time zones (a scheduled event's display time). Use TIMESTAMP for audit fields (created_at, updated_at) where the column represents a real universal moment — MySQL stores it as UTC and auto-converts to the session's time zone on read.
Question 21
Hard
Why does WHERE YEAR(order_date) = 2026 often perform worse than WHERE order_date >= '2026-01-01' AND order_date < '2027-01-01'?
What happens to the index on order_date?
Wrapping an indexed column in a function (YEAR, MONTH, DATE_FORMAT, etc.) disables index usage — the optimizer would have to apply the function to every row to evaluate the WHERE. The range version keeps the column 'naked' on the left side, so MySQL can use the B-Tree index to seek directly to the 2026 rows. This is the single most common performance trap with date columns.
Question 22
Easy
Write a query that returns today's date and yesterday's date.
Use CURDATE() and INTERVAL.
SELECT CURDATE() AS today,
       CURDATE() - INTERVAL 1 DAY AS yesterday;
Question 23
Medium
Given an orders(id, order_date, amount) table, write a query that returns the total revenue for each month of 2026, sorted chronologically.
GROUP BY DATE_FORMAT with ISO pattern.
SELECT DATE_FORMAT(order_date, '%Y-%m') AS month,
       SUM(amount) AS revenue
FROM orders
WHERE order_date >= '2026-01-01'
  AND order_date <  '2027-01-01'
GROUP BY month
ORDER BY month;
Question 24
Medium
Write a query to list students whose age is between 18 and 22 given a students(name, dob) table.
TIMESTAMPDIFF with YEAR.
SELECT name, dob,
       TIMESTAMPDIFF(YEAR, dob, CURDATE()) AS age
FROM students
WHERE TIMESTAMPDIFF(YEAR, dob, CURDATE()) BETWEEN 18 AND 22;
Question 25
Hard
Given sessions(user_id, login_at DATETIME), find users whose most recent login was more than 90 days ago.
Aggregate with MAX then HAVING with DATEDIFF.
SELECT user_id,
       MAX(login_at) AS last_seen,
       DATEDIFF(CURDATE(), MAX(login_at)) AS days_since
FROM sessions
GROUP BY user_id
HAVING days_since > 90;
Question 26
Medium
What is the output?
SELECT TIMEDIFF('14:30:00', '09:15:30');
TIMEDIFF returns a TIME value.
05:14:30
Question 27
Medium
What is the output?
SELECT WEEK('2026-01-01');
January 1 is in which week of the year?
0
Question 28
Hard
What is the output?
SELECT CONVERT_TZ('2026-04-16 00:30:00', '+05:30', '+00:00');
Subtract 5:30 from the given datetime.
2026-04-15 19:00:00
Question 29
Medium
What is the difference between NOW() and SYSDATE()?
Think about a query that runs for several seconds.
NOW() returns the time the current statement started executing — every call within one statement returns the same value. SYSDATE() returns the actual system clock at the moment the function is called — it can return different values within the same statement. NOW() is deterministic (safe for replication). SYSDATE() is not.

Mixed & Application Questions

Question 1
Easy
What does this return (today = 2026-04-16)?
SELECT CURDATE() - INTERVAL 30 DAY;
Subtract 30 days from April 16.
2026-03-17
Question 2
Easy
What is the output?
SELECT MONTHNAME('2026-07-20');
MONTHNAME returns the full English month name.
July
Question 3
Medium
Given employees(name, hire_date), what does this return?
SELECT name,
       TIMESTAMPDIFF(YEAR, hire_date, CURDATE()) AS tenure_yrs
FROM employees
WHERE hire_date = '2020-04-16';
Hired exactly 6 years ago today.
6
Question 4
Medium
What is the output?
SELECT DATE_FORMAT('2026-04-16', '%Y/%m/%d'),
       DATE_FORMAT('2026-04-16', '%d %M, %Y');
Two different format patterns.
2026/04/16 16 April, 2026
Question 5
Medium
Write a query that returns the number of orders placed each day for the last 7 days from orders(id, order_date).
GROUP BY order_date with a 7-day filter.
SELECT order_date, COUNT(*) AS order_count
FROM orders
WHERE order_date >= CURDATE() - INTERVAL 7 DAY
GROUP BY order_date
ORDER BY order_date;
Question 6
Medium
Given users(id, name, created_at), write a query that counts new signups per day-of-week (Monday-Sunday).
Use DAYNAME and GROUP BY.
SELECT DAYNAME(created_at) AS day_of_week,
       COUNT(*) AS signups
FROM users
GROUP BY day_of_week
ORDER BY FIELD(day_of_week,
               'Monday','Tuesday','Wednesday','Thursday',
               'Friday','Saturday','Sunday');
Question 7
Hard
What is the output?
SELECT DATE_FORMAT(NOW(), '%Y-Q%q');
Is %q a valid format code?
2026-Q (followed by a literal 'q' — MySQL treats unknown % codes literally)
Question 8
Hard
What is the output?
SELECT TIMESTAMPDIFF(DAY, '2026-02-15 23:00:00', '2026-02-16 01:00:00');
How many whole days between these datetimes?
0
Question 9
Hard
Given orders(id, customer_id, order_date, amount), write a query that returns the month-over-month revenue growth percentage for 2026.
Use a self-join on month or LAG (covered in Chapter 18). For now try the self-join pattern.
SELECT curr.month,
       curr.revenue,
       prev.revenue AS prev_revenue,
       ROUND((curr.revenue - prev.revenue) / prev.revenue * 100, 2) AS growth_pct
FROM (
  SELECT DATE_FORMAT(order_date, '%Y-%m') AS month,
         SUM(amount) AS revenue
  FROM orders
  WHERE YEAR(order_date) = 2026
  GROUP BY month
) curr
LEFT JOIN (
  SELECT DATE_FORMAT(order_date, '%Y-%m') AS month,
         SUM(amount) AS revenue
  FROM orders
  WHERE YEAR(order_date) = 2026
  GROUP BY month
) prev
  ON curr.month = DATE_FORMAT(DATE_ADD(STR_TO_DATE(CONCAT(prev.month,'-01'),'%Y-%m-%d'), INTERVAL 1 MONTH), '%Y-%m')
ORDER BY curr.month;
Question 10
Medium
What is the output?
SELECT EXTRACT(HOUR FROM '2026-04-16 14:23:07');
Extract only the hour component.
14
Question 11
Hard
Why is TIMESTAMP limited to years 1970-2038 while DATETIME supports 1000-9999?
Think about how TIMESTAMP is stored internally.
TIMESTAMP is stored as a 4-byte signed integer representing seconds since the Unix epoch (1970-01-01 UTC). A 32-bit signed integer can hold values up to 2^31 - 1 = 2,147,483,647, which translates to 2038-01-19 03:14:07 UTC — this is the famous 'Y2038 problem'. DATETIME is stored as 8 bytes of packed date/time components, giving it a much wider range but no time-zone awareness.

Multiple Choice Questions

MCQ 1
Which function returns the current date only, without the time?
  • A. NOW()
  • B. CURDATE()
  • C. TODAY()
  • D. CURTIME()
Answer: B
B is correct. CURDATE() returns a DATE with no time. NOW() returns DATETIME. CURTIME() returns only the time. TODAY() is not a MySQL function.
MCQ 2
What does DATEDIFF('2026-04-16', '2026-04-10') return?
  • A. 6 days
  • B. 6
  • C. -6
  • D. A TIME value 00:00:06
Answer: B
B is correct. DATEDIFF(a, b) returns a - b as an INTEGER number of days. No unit is appended. It can be negative if b > a.
MCQ 3
Which is the correct way to add 7 days to a date?
  • A. date + 7
  • B. date + INTERVAL 7 DAY
  • C. ADD_DAYS(date, 7)
  • D. date.addDays(7)
Answer: B
B is correct. Use the INTERVAL syntax or DATE_ADD(date, INTERVAL 7 DAY). Plain arithmetic (date + 7) sometimes appears to work but is unreliable and non-portable.
MCQ 4
Which DATE_FORMAT specifier produces a 4-digit year?
  • A. %y
  • B. %Y
  • C. %YYYY
  • D. %year
Answer: B
B is correct. Capital %Y is 4-digit, lowercase %y is 2-digit. The specifiers are single-letter.
MCQ 5
Which function returns the last day of the month for a given date?
  • A. END_OF_MONTH(date)
  • B. MONTH_END(date)
  • C. LAST_DAY(date)
  • D. EOM(date)
Answer: C
C is correct. LAST_DAY is the MySQL function. It correctly handles leap years.
MCQ 6
Which TIMESTAMPDIFF unit correctly computes age in years?
  • A. DAY
  • B. MONTH
  • C. YEAR
  • D. DECADE
Answer: C
C is correct. TIMESTAMPDIFF(YEAR, dob, CURDATE()) returns the exact completed years, respecting whether the birthday has passed in the current year.
MCQ 7
Why is WHERE YEAR(created_at) = 2026 considered an anti-pattern?
  • A. It is syntactically wrong
  • B. It prevents the optimizer from using an index on created_at
  • C. It returns duplicate rows
  • D. YEAR() is deprecated in MySQL 8
Answer: B
B is correct. Wrapping the indexed column in a function forces a full table scan. Rewrite as a range: created_at >= '2026-01-01' AND created_at < '2027-01-01'.
MCQ 8
Which MySQL column type stores values as UTC internally and auto-converts on read?
  • A. DATE
  • B. DATETIME
  • C. TIMESTAMP
  • D. TIME
Answer: C
C is correct. TIMESTAMP is time-zone aware: stored as UTC, converted to the session time zone on read. DATETIME is a literal wall-clock value with no TZ awareness.
MCQ 9
What does STR_TO_DATE('2026-13-01', '%Y-%m-%d') return?
  • A. 2027-01-01
  • B. An error
  • C. NULL
  • D. 2026-12-01
Answer: C
C is correct. Month 13 is invalid, so STR_TO_DATE returns NULL. It does not error, and it does not silently roll over to the next year.
MCQ 10
Which of these returns the quarter number (1-4) for a date?
  • A. QUARTER(date)
  • B. EXTRACT(QTR FROM date)
  • C. DATE_FORMAT(date, '%q')
  • D. Q(date)
Answer: A
A is correct. QUARTER(date) returns 1-4. MySQL's DATE_FORMAT has no %q specifier. EXTRACT(QUARTER FROM date) also works (full word), but not QTR.
MCQ 11
DAYOFWEEK in MySQL returns what for a Monday?
  • A. 0
  • B. 1
  • C. 2
  • D. 7
Answer: C
C is correct. DAYOFWEEK numbers Sunday=1, Monday=2, ..., Saturday=7. For Monday=0 style (ISO), use WEEKDAY() instead.
MCQ 12
What is the result of DATE_ADD('2026-01-31', INTERVAL 1 MONTH)?
  • A. 2026-02-31 (stored as-is)
  • B. 2026-03-03 (rolled over)
  • C. 2026-02-28 (clamped)
  • D. NULL
Answer: C
C is correct. MySQL clamps to the last valid day of the target month. Feb 31 does not exist, so it becomes Feb 28 (2026 is not a leap year). No rollover, no NULL.
MCQ 13
Why might CONVERT_TZ return NULL?
  • A. The input datetime is NULL
  • B. You used a named time zone like 'Asia/Kolkata' without loading the tz tables
  • C. The offset is out of range
  • D. All of the above
Answer: D
D is correct. CONVERT_TZ returns NULL for NULL input, for unknown named zones (fix by running mysql_tzinfo_to_sql), and for invalid offsets. Named zones require the tz tables to be populated.
MCQ 14
Which query correctly finds orders placed in Q2 2026 using a sargable predicate?
  • A. WHERE QUARTER(order_date) = 2 AND YEAR(order_date) = 2026
  • B. WHERE order_date BETWEEN '2026-04-01' AND '2026-06-30'
  • C. WHERE order_date >= '2026-04-01' AND order_date < '2026-07-01'
  • D. WHERE DATE_FORMAT(order_date, '%Y-Q') = '2026-Q2'
Answer: C
C is correct. It's sargable (the indexed column is not wrapped in a function) and uses a half-open range, which correctly includes the last day regardless of time component. B is close but fails for rows with times on June 30. A and D wrap the column in functions.
MCQ 15
Which function combo gives you the first day of the NEXT month?
  • A. LAST_DAY(d)
  • B. LAST_DAY(d) + INTERVAL 1 DAY
  • C. DATE_ADD(d, INTERVAL 1 MONTH)
  • D. DAY(d) + 1
Answer: B
B is correct. LAST_DAY gives the last day of the current month. Adding 1 day jumps to the 1st of the next month. This is the standard trick for monthly boundaries.
MCQ 16
Which function converts a Unix epoch integer to a DATETIME?
  • A. UNIX_TIMESTAMP()
  • B. FROM_UNIXTIME()
  • C. EPOCH_TO_DATE()
  • D. TO_TIMESTAMP()
Answer: B
B is correct. FROM_UNIXTIME(seconds) converts epoch to DATETIME. UNIX_TIMESTAMP() goes the opposite direction.
MCQ 17
What does TIMEDIFF return?
  • A. An INTEGER number of seconds
  • B. A TIME value
  • C. A DATETIME
  • D. A DECIMAL hours
Answer: B
B is correct. TIMEDIFF returns a TIME value like '05:14:30'. For seconds-as-integer, use TIMESTAMPDIFF(SECOND, a, b).
MCQ 18
Why does NOW() return the same value for every row within a single UPDATE statement?
  • A. It is cached globally
  • B. NOW() is evaluated once per statement to ensure deterministic, replication-safe behavior
  • C. It's a bug
  • D. Because UPDATE is fast
Answer: B
B is correct. NOW() is deterministic per statement — essential for replication and for keeping audit timestamps consistent across rows in a bulk update. Use SYSDATE() if you want the real clock per call.
MCQ 19
To GROUP BY month with correct chronological sorting, which format pattern should you use?
  • A. '%M %Y' (April 2026)
  • B. '%m-%Y' (04-2026)
  • C. '%Y-%m' (2026-04)
  • D. '%b-%y' (Apr-26)
Answer: C
C is correct. '%Y-%m' sorts alphabetically the same as chronologically. The others sort wrong — April comes before January alphabetically, and '04-2026' comes before '04-2025' only because of the month.
MCQ 20
Why does TIMESTAMP have a Y2038 problem?
  • A. MySQL was designed in the 1970s
  • B. It is stored as a 32-bit signed integer of seconds since 1970-01-01 UTC, which overflows at 2038-01-19
  • C. Because leap years confuse it
  • D. It cannot handle dates before 2000
Answer: B
B is correct. A 32-bit signed integer holds 2^31 - 1 = 2147483647 seconds, which maps to 2038-01-19 03:14:07 UTC. Many systems (including MySQL) are migrating to 64-bit timestamps to solve this.

Coding Challenges

Challenge 1: Orders From the Last 30 Days

Easy
Given orders(id, customer, order_date, amount), write a query that returns all orders placed in the last 30 days (inclusive of today), sorted by order_date descending.
Sample Input
orders rows: 6 sample rows across the last 2 months
Sample Output
All rows with order_date >= CURDATE() - INTERVAL 30 DAY.
Use a sargable range predicate. Do not wrap order_date in a function.
CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer VARCHAR(50),
  order_date DATE,
  amount DECIMAL(10,2)
);
INSERT INTO orders VALUES
  (1, 'Aarav Sharma',  '2026-04-15', 1200),
  (2, 'Priya Nair',    '2026-04-02',  850),
  (3, 'Rohan Mehta',   '2026-03-25', 2400),
  (4, 'Meera Krishnan','2026-03-10',  450),
  (5, 'Vikram Singh',  '2026-02-28', 3100);

SELECT *
FROM orders
WHERE order_date >= CURDATE() - INTERVAL 30 DAY
ORDER BY order_date DESC;

Challenge 2: Age From Date of Birth

Easy
Given students(id, name, dob), return each student's name, dob, and exact age in completed years as of today. Sort by age descending.
Sample Input
5 students with varied DOBs including one whose birthday is tomorrow.
Sample Output
Each row shows the student and their age in whole years.
Use TIMESTAMPDIFF, not DATEDIFF/365.
CREATE TABLE students (id INT PRIMARY KEY, name VARCHAR(50), dob DATE);
INSERT INTO students VALUES
  (1, 'Ishaan Gupta',  '2008-11-12'),
  (2, 'Kavya Reddy',   '2006-02-29'),
  (3, 'Arjun Pillai',  '2010-04-17'),
  (4, 'Neha Choudhary','2004-07-22'),
  (5, 'Diya Bhatt',    '2000-01-05');

SELECT name, dob,
       TIMESTAMPDIFF(YEAR, dob, CURDATE()) AS age
FROM students
ORDER BY age DESC;

Challenge 3: Revenue by Month of 2026

Easy
From sales(id, sold_at DATETIME, amount), return order count and total revenue for each month of 2026, sorted chronologically.
Sample Input
8 sales across Jan-April 2026.
Sample Output
One row per month with count and SUM(amount).
Use sortable format for GROUP BY. Filter sargably.
CREATE TABLE sales (id INT PRIMARY KEY, sold_at DATETIME, amount DECIMAL(10,2));
INSERT INTO sales VALUES
  (1, '2026-01-10 10:22:00', 1200),
  (2, '2026-01-25 15:40:00',  800),
  (3, '2026-02-03 09:10:00', 2200),
  (4, '2026-02-28 18:05:00', 1500),
  (5, '2026-03-12 11:30:00', 3100),
  (6, '2026-03-29 20:00:00',  950),
  (7, '2026-04-05 13:15:00', 1800),
  (8, '2026-04-15 16:45:00', 2650);

SELECT DATE_FORMAT(sold_at, '%Y-%m') AS month,
       COUNT(*) AS orders,
       SUM(amount) AS revenue
FROM sales
WHERE sold_at >= '2026-01-01' AND sold_at < '2027-01-01'
GROUP BY month
ORDER BY month;

Challenge 4: Inactive Users Report

Medium
Given sessions(user_id, last_login DATETIME), return user_id, last_login date, and days_inactive for users whose most recent login is more than 30 days ago. Sort by days_inactive DESC.
Sample Input
5 users with varied last_login values.
Sample Output
Only users with 30+ days of inactivity, most inactive first.
Use GROUP BY + HAVING. Do not include active users.
CREATE TABLE sessions (user_id INT, last_login DATETIME);
INSERT INTO sessions VALUES
  (101, '2026-04-15 09:12:00'),
  (102, '2026-03-05 14:20:00'),
  (103, '2026-04-10 11:00:00'),
  (104, '2026-01-20 08:30:00'),
  (105, '2026-03-14 22:15:00');

SELECT user_id,
       MAX(last_login)                           AS last_seen,
       DATEDIFF(CURDATE(), MAX(last_login))      AS days_inactive
FROM sessions
GROUP BY user_id
HAVING days_inactive > 30
ORDER BY days_inactive DESC;

Challenge 5: Sign-Ups by Day of Week

Medium
Given users(id, name, created_at DATETIME), return each weekday (Monday to Sunday) and the number of users who signed up on that weekday. Output in Mon-Sun order.
Sample Input
7 users spread across different weekdays.
Sample Output
7 rows, one per weekday, sorted Mon->Sun.
Use DAYNAME and custom ordering with FIELD.
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50), created_at DATETIME);
INSERT INTO users VALUES
  (1,'Aarav Sharma',  '2026-04-13 10:00:00'),  -- Monday
  (2,'Priya Nair',    '2026-04-14 09:30:00'),  -- Tuesday
  (3,'Rohan Mehta',   '2026-04-15 18:10:00'),  -- Wednesday
  (4,'Ananya Iyer',   '2026-04-16 07:22:00'),  -- Thursday
  (5,'Vikram Singh',  '2026-04-10 23:00:00'),  -- Friday
  (6,'Meera Krishnan','2026-04-11 12:00:00'),  -- Saturday
  (7,'Diya Bhatt',    '2026-04-12 19:30:00');  -- Sunday

SELECT DAYNAME(created_at) AS day_of_week,
       COUNT(*)             AS signups
FROM users
GROUP BY day_of_week
ORDER BY FIELD(day_of_week,
               'Monday','Tuesday','Wednesday','Thursday',
               'Friday','Saturday','Sunday');

Challenge 6: Monthly Retention Window

Medium
Given orders(id, customer_id, order_date), for each customer return the first and last order dates and the number of months between them (as a tenure measure).
Sample Input
Multiple orders per customer across several months.
Sample Output
customer_id, first_order, last_order, tenure_months.
Use MIN, MAX, and TIMESTAMPDIFF with MONTH unit.
CREATE TABLE orders (id INT PRIMARY KEY, customer_id INT, order_date DATE);
INSERT INTO orders VALUES
  (1, 101, '2025-01-10'),
  (2, 101, '2025-07-22'),
  (3, 101, '2026-03-05'),
  (4, 102, '2025-11-02'),
  (5, 102, '2026-02-14'),
  (6, 103, '2026-04-01');

SELECT customer_id,
       MIN(order_date)                                       AS first_order,
       MAX(order_date)                                       AS last_order,
       TIMESTAMPDIFF(MONTH, MIN(order_date), MAX(order_date)) AS tenure_months
FROM orders
GROUP BY customer_id
ORDER BY tenure_months DESC;

Challenge 7: Parse Mixed Date Strings

Hard
Given raw_upload(id, raw_date VARCHAR(30)) with dates in three formats ('16-04-2026', '05/04/2026', 'April 12, 2026'), return id, raw_date, and parsed_date (a proper DATE). Rows that cannot be parsed should show NULL for parsed_date.
Sample Input
4+ rows mixing the three formats plus one garbage string.
Sample Output
All rows with parsed_date populated where possible.
Use CASE with LIKE, STR_TO_DATE for each format. Handle invalid input gracefully.
CREATE TABLE raw_upload (id INT PRIMARY KEY, raw_date VARCHAR(30));
INSERT INTO raw_upload VALUES
  (1, '16-04-2026'),
  (2, '05/04/2026'),
  (3, 'April 12, 2026'),
  (4, '2026.04.09'),
  (5, 'not a date');

SELECT id, raw_date,
       CASE
         WHEN raw_date REGEXP '^[0-9]{2}-[0-9]{2}-[0-9]{4}{{CODING_CHALLENGES_HTML}}#39;    THEN STR_TO_DATE(raw_date, '%d-%m-%Y')
         WHEN raw_date REGEXP '^[0-9]{2}/[0-9]{2}/[0-9]{4}{{CODING_CHALLENGES_HTML}}#39;    THEN STR_TO_DATE(raw_date, '%d/%m/%Y')
         WHEN raw_date REGEXP '^[A-Za-z]+ [0-9]+, [0-9]{4}{{CODING_CHALLENGES_HTML}}#39;    THEN STR_TO_DATE(raw_date, '%M %d, %Y')
         WHEN raw_date REGEXP '^[0-9]{4}\\.[0-9]{2}\\.[0-9]{2}{{CODING_CHALLENGES_HTML}}#39; THEN STR_TO_DATE(raw_date, '%Y.%m.%d')
         ELSE NULL
       END AS parsed_date
FROM raw_upload;

Challenge 8: Global Webinar Display

Hard
Given webinars(id, topic, starts_utc DATETIME), show the start time for three time zones: IST (+05:30), Singapore (+08:00), and New York (-04:00). Also include a pretty IST display string like 'Thursday, 16 Apr 07:30 PM'.
Sample Input
3 webinars with UTC start times.
Sample Output
topic, utc, ist, sg, ny, pretty_ist.
Use CONVERT_TZ and DATE_FORMAT.
CREATE TABLE webinars (id INT PRIMARY KEY, topic VARCHAR(60), starts_utc DATETIME);
INSERT INTO webinars VALUES
  (1,'Python Masterclass','2026-04-20 13:30:00'),
  (2,'SQL Interview Prep','2026-04-22 14:00:00'),
  (3,'Web Dev Bootcamp',  '2026-04-25 03:00:00');

SELECT topic,
       starts_utc                                          AS utc,
       CONVERT_TZ(starts_utc,'+00:00','+05:30')            AS ist,
       CONVERT_TZ(starts_utc,'+00:00','+08:00')            AS sg,
       CONVERT_TZ(starts_utc,'+00:00','-04:00')            AS ny,
       DATE_FORMAT(CONVERT_TZ(starts_utc,'+00:00','+05:30'),
                   '%W, %d %b %h:%i %p')                   AS pretty_ist
FROM webinars
ORDER BY starts_utc;

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to master SQL and databases with a mentor?

Explore our MySQL Masterclass