SQL-Engineering-Handbook

02 — Date Extraction

Introduction

Once you can reliably retrieve “now,” the next skill is breaking any date apart into its component pieces — year, month, quarter, week, weekday. Almost every recurring business report is fundamentally a GROUP BY on some extracted date component: revenue by month, headcount by year, orders by weekday. This file covers the extraction functions that make that possible.


Concept Overview

Extraction functions take a DATE or DATETIME value and return one structured piece of it — a year as an integer, a month name as a string, a weekday as either a number or a name. They are the building block of every time-bucketed report.


Why This Exists

Raw dates are too granular for most reporting. A retailer doesn’t want “revenue on 2024-03-17” as a standalone fact — they want “revenue in March 2024” compared against “revenue in February 2024.” Extraction functions convert a precise timestamp into the coarser business period that a report actually needs to group by.


Business Context

A sales dashboard grouping transactions by QUARTER(order_date) produces the quarterly revenue trend line an executive team reviews every board meeting. An HR system grouping hires by MONTHNAME(hire_date) reveals seasonal hiring patterns. A logistics team grouping deliveries by DAYNAME(delivery_date) might discover that Friday deliveries have a disproportionately high failure rate.


Real Company Examples


Where It Is Used


Functions Covered

Function Returns Example ('2026-07-07')
YEAR(date) Four-digit year 2026
MONTH(date) Month number (1–12) 7
MONTHNAME(date) Full month name 'July'
DAY(date) Day of month (1–31) 7
DAYNAME(date) Full weekday name 'Tuesday'
QUARTER(date) Quarter number (1–4) 3
WEEK(date) Week number of the year 27 (mode-dependent)
WEEKDAY(date) Weekday index, 0 = Monday6 = Sunday 1
DAYOFYEAR(date) Day number within the year (1–366) 188

Syntax Explanation

SELECT
    YEAR(order_date)       AS order_year,
    QUARTER(order_date)    AS order_quarter,
    MONTHNAME(order_date)  AS order_month_name,
    DAYNAME(order_date)    AS order_weekday
FROM orders;

Each extraction function accepts a single date/datetime expression and returns a scalar. They can be applied directly to a column, to a computed expression, or to a literal date string.


Visual Explanation

Extracting nine parts from a single date

'2026-07-07'  (Tuesday, 188th day of the year)
      │
      ├── YEAR()        → 2026
      ├── QUARTER()     → 3
      ├── MONTH()       → 7
      ├── MONTHNAME()   → 'July'
      ├── WEEK()        → 27
      ├── DAY()         → 7
      ├── DAYNAME()     → 'Tuesday'
      ├── WEEKDAY()     → 1      (0 = Monday)
      └── DAYOFYEAR()   → 188

Step-by-Step Walkthrough

  1. Start from a raw DATE/DATETIME value in a column.
  2. Decide what grain the report needs: yearly, quarterly, monthly, weekly, or by weekday.
  3. Apply the matching extraction function inside SELECT for display, and the identical expression inside GROUP BY for aggregation.
  4. When two extractions are needed together for correct grouping (e.g., “monthly trend across multiple years”), combine YEAR() and MONTH() — grouping by MONTH() alone incorrectly merges January 2024 with January 2025.

Production Considerations


Performance Notes


Edge Cases


Common Mistakes


Interview Questions

  1. “How would you build a monthly revenue trend across three years of data without merging different years into the same bucket?” Group by both YEAR(order_date) and MONTH(order_date), not MONTH() alone.

  2. “Why might two teams get different weekly numbers from the same table?” WEEK() mode differences — one team may be using a Sunday-start mode, the other an ISO-8601 Monday-start mode.

  3. “What’s wrong with WHERE YEAR(order_date) = 2024 on a 50-million-row orders table?” It disables index usage on order_date, forcing a full table scan; a sargable range filter should be used instead.


Summary

Extraction functions convert precise dates into the business-meaningful periods that reports actually group by. The critical engineering judgments are: always pair YEAR() with sub-year extractions when spanning multiple years, be explicit about WEEK() mode, and never use extraction functions to filter an indexed column when a sargable range filter is available.


Practice Challenges

  1. Write a query that returns each employee’s hire year, hire quarter, and hire month name in three separate columns.
  2. Explain why GROUP BY MONTH(order_date) alone is dangerous on a table containing multiple years of data, and rewrite the GROUP BY clause to fix it.
  3. Write a sargable query to select all orders placed in Q1 2024 without wrapping the order_date column in QUARTER() or YEAR().

Further Reading


Previous: ← 01 — Current Date Functions Next: 03 — Date Calculations →