Home Functions EXTRACT()
SQL Date & Time Function

EXTRACT()

EXTRACT() is the ANSI standard function that pulls a single component, such as the year, month or day of week, out of a date or timestamp value.

MySQLPostgreSQLSQL Server
Returns: A number: the requested component of a date or timestamp (for example the year as an integer, or the epoch as a numeric value).

Syntax

EXTRACT(part FROM date)EXTRACT(YEAR FROM order_date)DATEPART(part, date) -- SQL Server equivalentDATENAME(part, date) -- SQL Server, returns the name as text
ParameterTypeRequiredDescription
part keyword yes The field to pull out: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DOW (day of week), DOY (day of year), QUARTER or EPOCH. It is a bare keyword, not a string in quotes.
date date or timestamp yes The date, time or timestamp value to read the component from. Can be a column, a literal or an expression.

How it works

EXTRACT(part FROM date) reads one field out of a date or timestamp and returns it as a number. Common parts are YEAR, MONTH, DAY, HOUR, MINUTE and SECOND, plus a few calendar helpers: QUARTER (1 to 4), DOW (day of week), DOY (day of year) and EPOCH (seconds since 1970-01-01 in PostgreSQL). The part is written as a bare keyword, so it is EXTRACT(YEAR FROM order_date), not EXTRACT('YEAR' FROM order_date).

It is part of the SQL standard, and both MySQL and PostgreSQL implement it directly. MySQL also ships shorthand functions such as YEAR(), MONTH() and DAY() that do the same job for a single field. Use whichever reads more clearly; the shorthands are handy but not portable.

SQL Server has no EXTRACT function. It uses DATEPART(part, date) to return the component as an integer, and DATENAME(part, date) to return it as text, for example the month name. If you are porting queries between engines, this is the line that usually needs to change. To reduce a date to a boundary rather than read a field, see DATE_FORMAT() and DATE_TRUNC().

Examples

Get the year from a date

-- ANSI standard, works in MySQL and PostgreSQL
SELECT EXTRACT(YEAR FROM order_date) AS order_year
FROM orders
WHERE id = 1;
Result
order_year
----------
      2026

Group sales by month using EXTRACT

SELECT EXTRACT(YEAR FROM order_date)  AS yr,
       EXTRACT(MONTH FROM order_date) AS mon,
       SUM(total) AS revenue
FROM orders
GROUP BY EXTRACT(YEAR FROM order_date),
         EXTRACT(MONTH FROM order_date)
ORDER BY yr, mon;
Result
yr   | mon | revenue
-----+-----+--------
2026 |   1 |  41250
2026 |   2 |  38700
2026 |   3 |  52990

Day of week and day of year

-- PostgreSQL: DOW is 0=Sunday .. 6=Saturday
SELECT EXTRACT(DOW FROM order_date) AS weekday,
       EXTRACT(DOY FROM order_date) AS day_of_year
FROM orders
WHERE id = 1;
Result
weekday | day_of_year
--------+------------
      5 |          64

Same query, three engines

-- MySQL and PostgreSQL (ANSI EXTRACT)
SELECT EXTRACT(YEAR FROM order_date) AS yr FROM orders;

-- MySQL shorthand
SELECT YEAR(order_date) AS yr FROM orders;

-- SQL Server has no EXTRACT: use DATEPART
SELECT DATEPART(YEAR, order_date) AS yr FROM orders;
Result
yr
----
2026

Quarter and epoch seconds

-- QUARTER returns 1..4; EPOCH (PostgreSQL) is
-- seconds since 1970-01-01 00:00:00 UTC
SELECT EXTRACT(QUARTER FROM order_date) AS q,
       EXTRACT(EPOCH FROM created_at)   AS unix_seconds
FROM orders
WHERE id = 1;
Result
q | unix_seconds
--+-------------
1 |  1772668800

Common mistakes

Wrong
-- Wrapping the indexed column in EXTRACT means the
-- index on order_date cannot be used: full scan
SELECT *
FROM orders
WHERE EXTRACT(YEAR FROM order_date) = 2026;
Right
-- Compare the raw column to a range instead, so the
-- index on order_date stays usable
SELECT *
FROM orders
WHERE order_date >= '2026-01-01'
  AND order_date <  '2027-01-01';

Applying a function to an indexed column in WHERE makes the predicate non-sargable, so the optimiser cannot use the index and falls back to a full scan. Rewrite it as a half-open range on the bare column. See how SQL indexes improve performance.

Wrong
-- Assuming DOW numbering is the same everywhere.
-- PostgreSQL: 0=Sunday. MySQL DAYOFWEEK: 1=Sunday.
-- SQL Server DATEPART(WEEKDAY): depends on DATEFIRST.
SELECT EXTRACT(DOW FROM order_date) FROM orders;
Right
-- Pin down the engine's numbering before you
-- compare it. In PostgreSQL, Friday is 5:
SELECT CASE EXTRACT(DOW FROM order_date)
         WHEN 0 THEN 'Sun' WHEN 6 THEN 'Sat'
         ELSE 'weekday' END AS kind
FROM orders;

Day-of-week numbering is not portable. PostgreSQL DOW is 0 (Sunday) to 6 (Saturday), MySQL DAYOFWEEK is 1 (Sunday) to 7 (Saturday), and SQL Server DATEPART(WEEKDAY, ...) depends on the SET DATEFIRST setting. Always confirm the base before doing arithmetic on it.

Wrong
-- SQL Server does not have EXTRACT: this errors
SELECT EXTRACT(MONTH FROM order_date)
FROM orders;
Right
-- Use DATEPART for a number, DATENAME for the name
SELECT DATEPART(MONTH, order_date)  AS mon_num,
       DATENAME(MONTH, order_date)  AS mon_name
FROM orders;

SQL Server has no EXTRACT function at all. Use DATEPART(part, date) when you want the component as an integer, and DATENAME(part, date) when you want its text label such as the month or weekday name.

Performance

The cost of EXTRACT() itself is tiny; the trap is where you put it. Calling EXTRACT(YEAR FROM order_date) = 2026 in a WHERE clause forces the engine to compute the year for every row, which makes the predicate non-sargable and prevents any index on order_date from being used. Prefer a half-open range such as order_date >= '2026-01-01' AND order_date < '2027-01-01'.

In the SELECT list, GROUP BY or ORDER BY, EXTRACT() is cheap and perfectly fine, because it runs once per row that already survived filtering. Grouping sales by EXTRACT(MONTH FROM order_date) does not hurt an index, since no filtering depends on it.

If you filter on a derived date part very often, some engines let you build an index on the expression itself (an expression or function-based index) or persist it as a generated column, which restores index use without rewriting every query.

Interview questions

What does the EXTRACT() function do and what is its syntax?

It pulls a single component out of a date or timestamp. The syntax is EXTRACT(part FROM date), where part is a bare keyword such as YEAR, MONTH, DAY, HOUR, DOW, DOY, QUARTER or EPOCH. It returns that component as a number.

Which databases support EXTRACT, and what is the SQL Server equivalent?

EXTRACT is part of the SQL standard and is supported by MySQL and PostgreSQL. SQL Server does not have it: use DATEPART(part, date) for the numeric component or DATENAME(part, date) for the text name.

-- MySQL / PostgreSQL
SELECT EXTRACT(YEAR FROM order_date) FROM orders;
-- SQL Server
SELECT DATEPART(YEAR, order_date) FROM orders;

Why can EXTRACT() in a WHERE clause slow a query down?

Wrapping an indexed date column in EXTRACT makes the condition non-sargable, so the optimiser cannot use the index and scans the whole table. Rewrite it as a range on the raw column, for example order_date >= '2026-01-01' AND order_date < '2027-01-01'.

How does EXTRACT differ from MySQL functions like YEAR() and MONTH()?

They do the same thing for a single field. YEAR(d) is equivalent to EXTRACT(YEAR FROM d). EXTRACT is the portable ANSI standard form; YEAR() and MONTH() are MySQL shorthands that will not run on PostgreSQL or SQL Server.

Is the day-of-week number returned by EXTRACT(DOW ...) the same across engines?

No. PostgreSQL DOW runs 0 (Sunday) to 6 (Saturday). MySQL DAYOFWEEK runs 1 (Sunday) to 7 (Saturday). SQL Server DATEPART(WEEKDAY, ...) depends on SET DATEFIRST. Always confirm the numbering before comparing it.

Master SQL, one function at a time

Browse the full SQL functions library, or learn the fundamentals with our free, structured courses.