SQLEXTRACTdatetutorial

Что такое EXTRACT в SQL? Год, месяц, день из даты для начинающих

EXTRACT — это «достань кусок из даты»: год, месяц, день, час, день недели. Простыми словами: как сгруппировать данные по году/месяцу, отфильтровать по дню недели, посчитать секунды через EPOCH. Сравнение с DATE_TRUNC и отличия PostgreSQL и MySQL.

3 мин чтенияСправочникSQL · EXTRACT · date · tutorial

EXTRACT — это «вытащи отдельный компонент из даты или времени». Год, месяц, день, час, день недели — что угодно из даты можно достать отдельным числом.

Это стандартный SQL-приём для группировок и фильтров: «сколько регистраций по месяцам», «выручка за каждый понедельник», «сколько секунд от epoch».

Зачем нужен EXTRACT

Дата — это сложный тип. В одной timestamp-строке зашит и год, и месяц, и день, и время. Часто нужна не вся дата целиком, а её кусок:

  • Группировка по году: «регистрации по годам».
  • Фильтр по дню недели: «события только в будни».
  • Расчёт через EPOCH: «сколько секунд прошло между событиями».

EXTRACT отвечает именно на эти задачи.

Базовый синтаксис

SELECT EXTRACT(YEAR FROM TIMESTAMP '2026-03-15 10:30:00');  -- 2026
SELECT EXTRACT(MONTH FROM DATE '2026-03-15');               -- 3
SELECT EXTRACT(DAY FROM DATE '2026-03-15');                 -- 15
SELECT EXTRACT(HOUR FROM TIMESTAMP '2026-03-15 10:30:00');  -- 10

Структура: EXTRACT(<поле> FROM <выражение>). Возвращает число.

Самые частые поля

Поле Что возвращает
YEAR Год
MONTH Месяц (1-12)
DAY День месяца (1-31)
HOUR Час (0-23)
MINUTE Минута (0-59)
SECOND Секунда (0-60, с микросекундами как дробь)
DOW День недели (0=воскресенье, 6=суббота)
ISODOW День недели по ISO (1=пн, 7=вс)
DOY День года (1-366)
WEEK Номер ISO-недели (1-53)
QUARTER Квартал (1-4)
EPOCH Секунд с 1970-01-01 UTC

Группировка по периодам

-- Регистрации по месяцам 2026 года
SELECT
  EXTRACT(YEAR FROM created_at) AS year,
  EXTRACT(MONTH FROM created_at) AS month,
  COUNT(*) AS regs
FROM users
WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'
GROUP BY 1, 2
ORDER BY 1, 2;

Альтернатива через DATE_TRUNC — короче и обычно удобнее:

SELECT
  DATE_TRUNC('month', created_at) AS month,
  COUNT(*) AS regs
FROM users
WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'
GROUP BY 1
ORDER BY 1;

DATE_TRUNC('month', date) — обрезает дату до начала месяца (2026-03-152026-03-01). Возвращает timestamp, удобно для UI.

EXTRACT — возвращает число. Удобно когда нужны отдельно year и month как разные колонки.

Фильтр по компоненту даты

-- Все события, случившиеся в марте (любого года)
SELECT * FROM events WHERE EXTRACT(MONTH FROM occurred_at) = 3;

-- Только понедельники
SELECT * FROM events WHERE EXTRACT(ISODOW FROM occurred_at) = 1;

-- Рабочие часы — пн-пт, 9-18
SELECT * FROM events
WHERE EXTRACT(ISODOW FROM occurred_at) BETWEEN 1 AND 5
  AND EXTRACT(HOUR FROM occurred_at) BETWEEN 9 AND 17;

Внимание: EXTRACT в WHERE мешает обычному индексу на occurred_at. На больших таблицах — либо functional index CREATE INDEX ON events (EXTRACT(MONTH FROM occurred_at)), либо переписать через диапазон:

-- Это использует обычный индекс
SELECT * FROM events
WHERE occurred_at >= '2026-03-01' AND occurred_at < '2026-04-01';

Диапазонная форма всегда быстрее, если возможна.

EPOCH и интервалы

EPOCH особенно полезен для измерения интервалов в секундах:

-- Сколько секунд между двумя timestamp'ами
SELECT EXTRACT(EPOCH FROM ('2026-03-15 10:30:00' - '2026-03-15 09:00:00'))::INTEGER;
-- → 5400 (1.5 часа)

-- Возраст пользователей в днях от регистрации
SELECT
  name,
  EXTRACT(EPOCH FROM (NOW() - created_at)) / 86400 AS days_since_signup
FROM users;

EXTRACT(EPOCH FROM x) для timestamp возвращает секунды с Unix epoch:

SELECT EXTRACT(EPOCH FROM TIMESTAMP '2026-03-15 12:00:00');
-- → 1773993600

Пример с таблицей

orders:

id created_at amount
1 2026-01-15 10:00:00 100
2 2026-02-03 14:00:00 250
3 2026-02-20 11:30:00 80
4 2026-03-05 09:00:00 500

Сводка по месяцам:

SELECT
  EXTRACT(MONTH FROM created_at) AS month,
  COUNT(*) AS orders_count,
  SUM(amount) AS total
FROM orders
GROUP BY 1
ORDER BY 1;
month orders_count total
1 1 100
2 2 330
3 1 500

Отличия диалектов

MySQL не поддерживает EXTRACT(EPOCH FROM …). Аналог — UNIX_TIMESTAMP(date):

-- MySQL
SELECT UNIX_TIMESTAMP('2026-03-15 12:00:00');  -- 1773993600
SELECT YEAR('2026-03-15');     -- 2026
SELECT MONTH('2026-03-15');    -- 3
SELECT DAYOFWEEK('2026-03-15'); -- 1=воскресенье в MySQL

В MySQL также есть YEAR(), MONTH(), DAY(), HOUR() — короткие функции для отдельных компонентов.

SQLite не имеет EXTRACT. Используют STRFTIME:

SELECT STRFTIME('%Y', '2026-03-15');  -- '2026'
SELECT STRFTIME('%m', '2026-03-15');  -- '03'
SELECT STRFTIME('%w', '2026-03-15');  -- день недели, 0=воскресенье

SQL ServerDATEPART:

SELECT DATEPART(year, '2026-03-15');   -- 2026
SELECT DATEPART(month, '2026-03-15');  -- 3

Частые ошибки новичков

1. EXTRACT в WHERE без functional index. Делает full scan. Перепиши через диапазон если возможно (см. выше).

2. DOW vs ISODOW. EXTRACT(DOW) — 0=воскресенье. EXTRACT(ISODOW) — 1=понедельник, 7=воскресенье. Если хочешь «нормальный» календарный понедельник — используй ISODOW.

3. Часовые пояса. EXTRACT(HOUR FROM TIMESTAMPTZ) использует timezone сессии. Если в БД timestamp UTC, а пользователь в Москве — EXTRACT(HOUR ...) без AT TIME ZONE даст UTC-часы, не московские.

-- Час в московском времени
EXTRACT(HOUR FROM tstz AT TIME ZONE 'Europe/Moscow')

4. EPOCH возвращает дробное. Для timestamp с микросекундами — 1773993600.123456. Если нужен integer Unix timestamp — каст: EXTRACT(EPOCH FROM …)::BIGINT.

5. WEEK у разных БД отличается. PostgreSQL EXTRACT(WEEK) — ISO-неделя. MySQL WEEK(date) — несколько mode'ов в зависимости от настроек. При портировании проверяй.

6. Quarter/Year в группировках. GROUP BY EXTRACT(QUARTER FROM x) без EXTRACT(YEAR FROM x) смешает Q1 разных лет в одну группу. Всегда добавляй год для корректности.

Мини-резюме

  • EXTRACT(<поле> FROM <дата>) — достать год, месяц, день, час и т.д. как число.
  • Самые частые поля: YEAR, MONTH, DAY, HOUR, ISODOW, EPOCH.
  • ISODOW (1=пн, 7=вс) — обычно то, что хочешь, а не DOW (0=вс).
  • EXTRACT(EPOCH FROM ...) — секунды от Unix-epoch или из интервала. Для целого числа — ::BIGINT.
  • Для группировок по периоду часто удобнее DATE_TRUNC('month', x) — возвращает timestamp начала периода.
  • В WHERE — диапазонная форма (>= '2026-03-01' AND < '2026-04-01') быстрее, чем EXTRACT, потому что использует индекс.
  • В MySQL для EPOCH — UNIX_TIMESTAMP. В SQLite — STRFTIME. В SQL Server — DATEPART.

Закрепи на практике

Решай задачи в SQL-тренажёре с мгновенной проверкой и подсказками.

Открыть тренажёр