SQLQuokka
Start practicing
QuestionsLearnSandboxFeaturesRoadmapFAQ
SQL Concept

SQL Date Functions: Grouping, Filtering and Extracting Dates

Dates appear in nearly every product and analytics question: monthly revenue, users active in the last 7 days, time between events. The core ideas are the same everywhere, but MySQL and PostgreSQL name many date functions differently, so it pays to know both.

Examples run in MySQL 8 and PostgreSQL · Updated

In short

  • EXTRACT(MONTH FROM d) and EXTRACT(YEAR FROM d) work in both databases.
  • Filter ranges with >= start AND < next_start to avoid edge cases.
  • Group by an extracted part to get per-month or per-year totals.
  • Formatting and date arithmetic functions differ between MySQL and PostgreSQL.

Portable building blocks

EXTRACT(part FROM date) pulls out a year, month, day or hour and works the same in MySQL and PostgreSQL. Comparing dates with >= and < also works everywhere.

For ranges, prefer order_date >= '2025-02-01' AND order_date < '2025-03-01' over BETWEEN with the last day of the month: it stays correct for timestamps and month lengths.

MySQL vs PostgreSQL

Format as text: DATE_FORMAT(d, '%Y-%m') in MySQL; TO_CHAR(d, 'YYYY-MM') in PostgreSQL.

Days between dates: DATEDIFF(a, b) in MySQL; a - b in PostgreSQL.

Add an interval: DATE_ADD(d, INTERVAL 7 DAY) in MySQL; d + INTERVAL '7 days' in PostgreSQL.

Start of month: DATE_FORMAT(d, '%Y-%m-01') in MySQL; DATE_TRUNC('month', d) in PostgreSQL.

The example tables

Every example on this page uses these tables. They are small on purpose, so you can check each result by eye.

orders

order_idcustomer_idorder_dateamount
10112025-01-05120
10212025-01-2080
10322025-01-07200
10412025-02-02150
10532025-02-1090
10622025-02-2560
10732025-03-01130
10812025-03-0340

employees

emp_idnamedept_idsalarymanager_idhire_date
1Aarav1095000NULL2021-03-01
2Diya108800012022-06-15
3Kabir107200012023-01-10
4Meera2064000NULL2020-11-20
5Rohan205800042024-02-05
6Isha3061000NULL2022-09-12
7Arjun206400042023-07-30
8ZoyaNULL52000NULL2024-05-01

Examples

Orders and revenue per month

Group on the extracted month. Use the same expression in SELECT and GROUP BY.

SELECT EXTRACT(MONTH FROM order_date) AS month,
       COUNT(*) AS orders,
       SUM(amount) AS revenue
FROM orders
GROUP BY EXTRACT(MONTH FROM order_date)
ORDER BY month;
Result
monthordersrevenue
13400
23300
32170

A safe date range

Everything in February 2025: on or after the 1st, and strictly before March 1st.

SELECT order_id, order_date, amount
FROM orders
WHERE order_date >= '2025-02-01' AND order_date < '2025-03-01'
ORDER BY order_date;
Result
order_idorder_dateamount
1042025-02-02150
1052025-02-1090
1062025-02-2560

Filter by year

Employees hired in 2023 or later.

SELECT name, hire_date, EXTRACT(YEAR FROM hire_date) AS hire_year
FROM employees
WHERE EXTRACT(YEAR FROM hire_date) >= 2023
ORDER BY hire_date;
Result
namehire_datehire_year
Kabir2023-01-102023
Arjun2023-07-302023
Rohan2024-02-052024
Zoya2024-05-012024

Common mistakes

  • Grouping by month only. Grouping by month number merges January 2024 with January 2025. Group by year and month together when data spans years.
  • BETWEEN with timestamps. BETWEEN '2025-02-01' AND '2025-02-28' misses orders later in the day on the 28th when the column is a timestamp.
  • Mixing dialects. DATEDIFF and DATE_FORMAT fail in PostgreSQL; TO_CHAR and DATE_TRUNC fail in MySQL. Check which database the interview uses.

Practise Date Functions

Interview questions that use this concept, easiest first. Each one has the step-by-step visualizer and answer checking.

  1. Daily Active Users (DAU)

    Compute the daily count of unique active users from raw product activity event timestamps.

    Easy✓ Solved
  2. Rising Temperature

    Find all dates where the temperature was higher than the previous day using DATEDIFF.

    Easy✓ Solved
  3. Active Users in Last 7 Days

    Filter rolling active accounts by comparing timestamp with CURRENT_DATE interval arithmetic.

    Easy✓ Solved
  4. Amazon: Late Shipments Audit

    Identify orders delivered past their guaranteed delivery date and calculate the number of days late.

    Easy✓ Solved
  5. Listing Booking Windows

    Count each listing's bookings in the last 90 days, the last 365 days and all time.

    Easy✓ Solved
  6. Monthly Listing Ratings

    Average star rating for each listing in each month.

    Easy✓ Solved

Questions people ask

How do I get the month name?
MySQL: MONTHNAME(d) or DATE_FORMAT(d, '%M'). PostgreSQL: TO_CHAR(d, 'Month').
How do I find activity in the last 7 days?
MySQL: d >= CURDATE() - INTERVAL 7 DAY. PostgreSQL: d >= CURRENT_DATE - INTERVAL '7 days'.