EOMONTH (Transact-SQL)
Эта функция возвращает последний день месяца, содержащего указанную дату, с необязательным смещением.
Для вычисления начала месяца можно использовать DATETRUNC .
Синтаксис
EOMONTH ( start_date [ , month_to_add ] )
Сведения о синтаксисе Transact-SQL для SQL Server 2014 (12.x) и более ранних версиях см . в документации по предыдущим версиям.
Аргументы
start_date
Выражение даты, задающее дату, для которой необходимо возвратить последний день месяца.
month_to_add
Необязательное целочисленное выражение, задающее количество месяцев, добавляемых к параметру start_date.
Если аргумент month_to_add имеет значение, то EOMONTH добавляет указанное число месяцев к значению start_date и возвращает последний день месяца, соответствующего полученной дате. Если это дополнение переполнено допустимым диапазоном дат, возникает EOMONTH ошибка.
Типы возвращаемых данных
date
Замечания
Функция EOMONTH может удалена к экземплярам под управлением SQL Server 2012 (11.x) и более поздних версий. Он не может удаленно использовать экземпляры с версией до SQL Server 2012 (11.x).
Примеры
А. EOMONTH с явным типом datetime
DECLARE @date DATETIME = '12/1/2022'; SELECT EOMONTH ( @date ) AS Result; GO
Result ------------ 2022-12-31 (1 row(s) affected)
B. EOMONTH со строковым параметром и неявным преобразованием
DECLARE @date VARCHAR(255) = '12/1/2022'; SELECT EOMONTH ( @date ) AS Result; GO
Result ------------ 2022-12-31 (1 row(s) affected)
C. Функция EOMONTH с параметром month_to_add и без него
Значения в этих результирующих наборах отражают дату выполнения между 12/01/2022 и 12/31/2022 (включительно).
DECLARE @date DATETIME = GETDATE(); SELECT EOMONTH ( @date ) AS 'This Month'; SELECT EOMONTH ( @date, 1 ) AS 'Next Month'; SELECT EOMONTH ( @date, -1 ) AS 'Last Month'; GO
This Month ----------------------- 2022-12-31 (1 row(s) affected) Next Month ----------------------- 2022-01-31 (1 row(s) affected) Last Month ----------------------- 2022-11-30 (1 row(s) affected)
Обратная связь
Были ли сведения на этой странице полезными?
SQL: Получить последнюю запись даты и времени в таблице
Для получения самой последней записи лучше упорядочить данные по дате и времени в обратном порядке, а затем извлечь первую строку из результата.
В MySQL выполните следующий запрос:
Скопировать код
SELECT * FROM ваша_таблица ORDER BY ваше_поле_даты_времени DESC LIMIT 1;
А для SQL Server подойдёт вот такой вариант:
Скопировать код
SELECT TOP 1 * FROM ваша_таблица ORDER BY ваше_поле_даты_времени DESC;
Такие запросы помогают быстро выделять последние записи в базе.
Когда требуются последние записи по определенным критериям
Если требуется достать дату и время последней записи для каждой категории, воспользуйтесь сочетанием GROUP BY с функцией MAX():
Скопировать код
SELECT имя_файла, статус, MAX(дата_последнего_изменения) AS максимальная_дата FROM ваша_таблица GROUP BY имя_файла, статус;
Для фильтрации по конкретному статусу используйте условие HAVING:
Скопировать код
SELECT имя_файла, статус, MAX(дата_последнего_изменения) AS максимальная_дата FROM ваша_таблица GROUP BY имя_файла, статус HAVING статус = 'Активный';
Такие запросы становятся особенно полезными, когда данные группируются по различным статусам или категориям.
Работа с большими наборами данных
При работе с большим объёмом данных можно использовать оконные функции, например, ROW_NUMBER(), чтобы улучшить производительность:
Скопировать код
WITH ОтранжированныеЗаписи AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY имя_файла ORDER BY дата_последнего_изменения DESC) AS rn FROM ваша_таблица ) SELECT * FROM ОтранжированныеЗаписи WHERE rn = 1;
LAST_VALUE() — ещё одна функция, методично работающая с OVER() и PARTITION BY:
Скопировать код
SELECT DISTINCT имя_файла, LAST_VALUE(дата_последнего_изменения) OVER (PARTITION BY имя_файла ORDER BY дата_последнего_изменения RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ПоследняяЗапись FROM ваша_таблица;
Гарантией правильности выполнения запроса является присвоение псевдонимов столбцам и проверка результатов с тестовыми данными.
Применение подзапросов без страха и риска
При использовании подзапросов, которые коррелируют с основным запросом, имейте в виду их влияние на производительность:
SQL-запрос: последняя дата входа для каждого пользователя
Чтобы эффективно определить последнюю запись каждого пользователя, воспользуйтесь функцией ROW_NUMBER() в SQL, корректно используя её в подзапросе. Ранжируйте записи, сортируя их по дате в обратном порядке, с применением PARTITION BY user_id . Затем отфильтруйте результаты так, чтобы остались только записи на первых позициях.
Скопировать код
SELECT user_id, record_date FROM ( SELECT user_id, record_date, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY record_date DESC) as rn FROM records ) WHERE rn = 1;
Ваш путь к результату:
- Используйте ROW_NUMBER() , чтобы назначить каждой дате записи уникальный порядковый номер, подобно выбору VIP-мест на концерте.
- PARTITION BY user_id позволяет разделить записи на отдельные группы для каждого пользователя, словно каждый из них находится в своём отдельном VIP-клубе.
- Сортировка ORDER BY record_date DESC позиционирует на первом месте самую последнюю дату. Будьте аккуратны, путешественники во времени!
- Фильтруя с помощью WHERE rn = 1 , мы отбираем лишь самые свежие записи для каждого пользователя. Нам нужны только актуальные данные.
Альтернативные пути, когда одного решения недостаточно
Если вам нужно функционировать в разных SQL-средах или работать с обширными данными, рассмотрите альтернативные варианты:
Эффективное объединение для улучшения производительности
Если скорость для вас важна, особенно когда дело касается индексированных полей, примените внутреннее соединение с подзапросом, который вычисляет максимальную дату:
Скопировать код
SELECT t.* FROM records t INNER JOIN ( SELECT user_id, MAX(record_date) AS MaxDate FROM records GROUP BY user_id /* Королю-пользователю достается только лучшее. Да здравствует MaxDate! */ ) AS groupedRecords ON t.user_id = groupedRecords.user_id AND t.record_date = groupedRecords.MaxDate;
Такой подход обеспечивает высокую производительность благодаря эффективности соединений и использованию максимальных значений дат. Это схоже с участием в гонке на скоростном гепарде.
Коррелированный подзапрос для обеспечения обратной совместимости
Для обеспечения максимальной совместимости попробуйте коррелированный подзапрос, который обходится без оконных функций:
Скопировать код
SELECT t1.* FROM records t1 WHERE t1.record_date = ( SELECT MAX(t2.record_date) FROM records t2 WHERE t2.user_id = t1.user_id /* "Мы так похожи", – как бы говорит t1 t2. */ );
Скорость обработки может быть невелика, впрочем, обратная совместимость гарантированно высока.
Находим идеальный баланс
Итоговый выбор метода решения должен основываться на балансе между элегантностью решения и его производительностью. Несмотря на то что ROW_NUMBER() компактна и быстра для обработки малых объемов данных, она может снижать скорость обработки больших объемов информации. В таких ситуациях на первый план выходят внутренние соединения и коррелированные подзапросы, особенно при работе с индексированными полями.
Визуализация
Представьте, что перед вами стоит очередь покупателей на кассе. Каждый из них сканирует штрихкод своей покупки, оставляя после себя временной отпечаток. Наша цель — определить последний временной отпечаток для каждого покупателя:
Как получить последнюю по дате запись (SQLite)?
У меня есть таблица price (id, link, name, cost, date) . В столбце name содержатся имена товаров, в столбце cost — цена на соответствующий товар. Эти цены с некоторой периодичностью добавляются в таблицу. Мне необходимо вытащить из таблицы последнюю запись конкретного товара по дате. Как я это могу сделать?
Отслеживать
задан 26 янв 2023 в 0:13
55 5 5 бронзовых знаков
order by date limit 1
26 янв 2023 в 1:49
Последняя по дате = первая по убыванию дат. Первая = limit 1 | first 1 | top 1, в зависимости от диалекта sql. По убыванию дат = order by date desc.
26 янв 2023 в 3:42
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
SELECT * FROM price WHERE name = 'product_name' ORDER BY date DESC LIMIT 1;
запрос сначала выбирает все записи с именем товара product_name , затем сортирует их по дате в порядке убывания и возвращ. только одну посл. запись с помощью оператора LIMIT 1 .
SELECT * FROM price p1 WHERE date = (SELECT MAX(date) FROM price p2 WHERE p1.name=p2.name AND p1.name='product_name')
SELECT * FROM (SELECT * FROM price WHERE name = 'product_name' ORDER BY date DESC) as temp_table GROUP BY name
Еще одно решение может быть функции для вашей СУБД, например ROW_NUMBER() в SQL, DENSE_RANK() в Oracle или RANK() в MySQL.
WITH temp_table AS ( SELECT id, link, name, cost, date, ROW_NUMBER() OVER (PARTITION BY name ORDER BY date DESC) as rn FROM price ) SELECT * FROM temp_table WHERE name = 'product_name' and rn = 1;
Предложенный мной ранее запрос с использованием оператора GROUP BY может возвращать неожиданный результат, если таблица price содержит несколько записей с одинаковым именем товара и датой, так как в этом случае неопределенно, какую из этих записей вернет запрос. Есть несколько других способов решить эту задачу. Один из них — это использование сортировки и оператора LIMIT 1 в запросе. Например:
SELECT id, link, name, cost, date FROM price WHERE name = 'product_name' ORDER BY date DESC LIMIT 1;
Этот запрос выбирает все записи с именем товара ‘product_name’, сортирует их по дате в порядке убывания и возвращает только одну последнюю запись с помощью оператора LIMIT 1.
Другой способ — подзапрос с макс. датой:
SELECT id, link, name, cost, date