Текущая дата минус день, месяц или год в SQL
В SQL Server из даты вычитают функцией DATEADD с отрицательным числом. Отдельной DATESUB в T-SQL нет:
SELECT DATEADD(day, -1, GETDATE()); -- сейчас минус 1 день
SELECT DATEADD(month, -1, GETDATE()); -- сейчас минус 1 месяц
SELECT DATEADD(year, -1, GETDATE()); -- сейчас минус 1 год
SELECT DATEADD(minute, -30, GETDATE()); -- сейчас минус 30 минут
Синтаксис: DATEADD(datepart, number, date) (документация Microsoft). С положительным числом дата сдвигается вперёд: DATEADD(month, 5, GETDATE()) — дата через пять месяцев.
Разницу между двумя датами считает DATEDIFF(day, @from, @to): это число дней между ними. Функция считает переходы через границу периода, а не полные периоды, поэтому DATEDIFF(year, '20251231', '20260101') вернёт 1, хотя прошёл один день.
Вчерашняя дата без времени
GETDATE() возвращает дату вместе со временем. Чтобы получить вчерашнюю дату, сначала приведите значение к date:
-- сегодня, без времени
SELECT CAST(GETDATE() AS date);
-- вчера
SELECT DATEADD(day, -1, CAST(GETDATE() AS date));
-- вчера, SQL Server 2025
SELECT DATEADD(day, -1, CURRENT_DATE);
С SQL Server 2025 в T-SQL есть функция CURRENT_DATE: она делает то же, что CAST(GETDATE() AS date), и возвращает date (документация Microsoft). Есть она и в Azure SQL Database, и в Azure SQL Managed Instance. В SQL Server 2022 и более ранних версиях её нет: 2022 отвечает ошибкой «Incorrect syntax near the keyword 'CURRENT_DATE'».
DATEADD возвращает тот же тип, что получил: datetime для GETDATE(), date для date. Строку SQL Server читает как datetime, поэтому пишите её в формате 'yyyymmdd': если язык сеанса русский, немецкий или британский, '2026-11-03' превратится в 11 марта.
GETDATE минус 1 день в WHERE
Записи за последние 24 часа:
SELECT * FROM Orders
WHERE CreatedAt >= DATEADD(day, -1, GETDATE());
Записи за вчера, с полуночи до полуночи:
SELECT * FROM Orders
WHERE CreatedAt >= DATEADD(day, -1, CAST(GETDATE() AS date))
AND CreatedAt < CAST(GETDATE() AS date);
Столбец не оборачивайте в функции, арифметику держите по другую сторону от знака сравнения. Я сравнил планы на SQL Server 2022 с индексом по CreatedAt: такой диапазон даёт Index Seek, а DATEDIFF(day, CreatedAt, GETDATE()) = 1 и CONVERT(varchar, CreatedAt, 120) читают индекс целиком. CAST(CreatedAt AS date) = ... — исключение, с ним SQL Server тоже ищет по индексу. Но полуоткрытый интервал >= начало AND < конец одинаково работает в любой СУБД.
С переменной DECLARE @today date индекс может не сработать: оптимизатор строит план, не зная её значения, и считает, что под условие попадёт фиксированная доля таблицы. В моём тесте SELECT * с переменной прочитал весь кластерный индекс. Если переменная нужна, допишите OPTION (RECOMPILE).
Не закрывайте день условием BETWEEN ... AND '23:59:59.999': при сравнении с datetime строка '23:59:59.999' округлится до следующей полуночи, и в выборку попадут строки ровно на 00:00:00 сегодняшнего дня.
Текущая дата минус год или месяц
-- тот же день год назад
SELECT DATEADD(year, -1, CAST(GETDATE() AS date));
SELECT DATEADD(month, -1, '20260331'); -- 2026-02-28 00:00:00.000
SELECT DATEADD(year, -1, '20280229'); -- 2027-02-28 00:00:00.000
Если такого числа в нужном месяце нет, DATEADD вернёт последний день месяца.
В SQL Server 2022 появилась функция DATETRUNC, она считает начало месяца:
-- начало этого месяца
SELECT DATETRUNC(month, GETDATE());
-- начало прошлого месяца
SELECT DATEADD(month, -1, DATETRUNC(month, GETDATE()));
-- последний день прошлого месяца
SELECT EOMONTH(GETDATE(), -1);
В старых версиях берите связку DATEADD и DATEDIFF из поста про начало месяца в MS SQL.
GETDATE, SYSDATETIME или CURRENT_TIMESTAMP
CURRENT_TIMESTAMP— ANSI-имя дляGETDATE(): тот жеdatetimeс точностью около 3 мс. Текущий timestamp минус день —DATEADD(day, -1, CURRENT_TIMESTAMP).SYSDATETIME()возвращаетdatetime2(7), у секунд в нём семь знаков после запятой.GETUTCDATE()иSYSUTCDATETIME()возвращают время в UTC. Azure SQL Database по умолчанию работает в UTC, поэтому там иGETDATE()вернёт UTC.
Значения datepart
year(yy,yyyy) — годquarter(qq,q) — кварталmonth(mm,m) — месяцdayofyear(dy,y) — день годаday(dd,d) — деньweek(wk,ww) — неделяweekday(dw,w) — день неделиhour(hh) — часminute(mi,n) — минутаsecond(ss,s) — секундаmillisecond(ms) — миллисекундаmicrosecond(mcs) — микросекундаnanosecond(ns) — наносекунда
В DATEADD значения dayofyear, day и weekday одинаково прибавляют дни. microsecond и nanosecond не работают с datetime, а значит и с GETDATE().
Текущая дата минус день в PostgreSQL, MySQL, SQLite и Oracle
Запросы для PostgreSQL 16, MySQL 8.4 и SQLite 3.51 я прогнал сам, Oracle сверил с документацией.
PostgreSQL
SELECT CURRENT_DATE - 1; -- сегодня минус день
SELECT now() - interval '1 day'; -- сейчас минус сутки
SELECT CURRENT_DATE - interval '1 month'; -- сегодня минус месяц
Дата минус интервал даёт timestamp: CURRENT_DATE - INTERVAL '1 day' — это вчерашняя полночь. Нужна дата — допишите ::date.
MySQL
SELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY); -- сегодня минус день
SELECT NOW() - INTERVAL 1 DAY; -- сейчас минус сутки
SELECT DATE_SUB(CURDATE(), INTERVAL 1 MONTH); -- сегодня минус месяц
Не пишите CURDATE() - 1: MySQL превратит дату в число, и 1 ноября получится 20261100.
SQLite
SELECT date('now', '-1 day'); -- сегодня минус день
SELECT datetime('now', '-1 day'); -- сейчас минус сутки
SELECT date('now', '-1 month'); -- сегодня минус месяц
'now' — это UTC, для местного времени добавьте 'localtime'. date('2026-03-31', '-1 month') вернёт 2026-03-03. С версии 3.46 добавьте последним аргументом 'floor' и получите 2026-02-28.
Oracle
SELECT TRUNC(SYSDATE) - 1 FROM dual; -- сегодня минус день
SELECT SYSDATE - 1 FROM dual; -- сейчас минус сутки
SELECT ADD_MONTHS(TRUNC(SYSDATE), -1) FROM dual; -- сегодня минус месяц
Число здесь означает дни, поэтому SYSDATE - 1/24 — час назад. Год назад — ADD_MONTHS(SYSDATE, -12). SYSDATE - INTERVAL '1' MONTH 31 марта упадёт с ошибкой: 31 февраля не бывает.
Где ошибаются в T-SQL
GETDATE() - 1работает сdatetime, аSYSDATETIME() - 1падает с ошибкой «Operand type clash: datetime2 is incompatible with int». БеритеDATEADD.CURRENT_DATE - 1работает в PostgreSQL, но в T-SQL кdateнельзя прибавить число: SQL Server 2025 выдаст ошибку «Operand type clash: date is incompatible with int». ПишитеDATEADD(day, -1, CURRENT_DATE).m— это месяц, а не минута. Минута —miилиn.datepartнельзя передать в переменной:DATEADD(@part, -1, GETDATE())падает с ошибкой «Invalid parameter 1 specified for dateadd». Варианты перебирайте вCASE.