Получить записи прошлого месяца на сервере SQL - PullRequest
64 голосов
/ 15 сентября 2009

Я хочу получить записи за последний месяц, основываясь на моей таблице в базе данных [member] поле "date_created".

Что такое sql для этого?

Для уточнения, в прошлом месяце - с 8 января 2009 года по 31 марта 2009 года

Если сегодня 3/1/2010, мне нужно получить записи с 1 января 2009 года по 31 декабря 2009 года.

Ответы [ 19 ]

92 голосов
/ 15 сентября 2009
SELECT * 
FROM Member
WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, date_created) = DATEPART(yyyy, DATEADD(m, -1, getdate()))

Вам нужно проверить месяц и год.

76 голосов
/ 10 июня 2014

Все существующие (рабочие) ответы имеют одну из двух проблем:

  1. Они будут игнорировать индексы для столбца, в котором выполняется поиск
  2. Завещание (потенциально) выберет данные, которые не предназначены, молча повреждая ваши результаты.

1. Игнорируемые индексы:

В большинстве случаев, когда для искомого столбца вызывается функция (в том числе неявно, как для CAST), оптимизатор должен игнорировать индексы столбца и выполнять поиск по каждой записи. Вот быстрый пример:

Мы имеем дело с метками времени, и большинство РСУБД, как правило, хранят эту информацию в виде некоторого возрастающего значения, обычно счетчика long или BIGINTEGER в милли / наносекундах. Текущее время, таким образом, выглядит / сохраняется так:

1402401635000000  -- 2014-06-10 12:00:35.000000 GMT

Вы не видите значения 'Year' ('2014') там, не так ли? На самом деле, есть довольно сложная математика для перевода туда-сюда. Таким образом, если вы вызываете какую-либо функцию извлечения / даты в столбце поиска, сервер должен выполнить всю эту математику, чтобы выяснить, можете ли вы включить ее в результаты. Для небольших таблиц это не проблема, но с уменьшением процента выбранных строк это становится все больше и больше. Затем в этом случае вы делаете это во второй раз, спрашивая о MONTH ... ну, вы поняли.

2. Непреднамеренные данные:

В зависимости от конкретной версии SQL Server и типов данных столбцов, использование BETWEEN (или аналогичных включающих верхних диапазонов: <=) может привести к неправильному выбору данных . По сути, вы можете в конечном итоге включить данные с полуночи «следующего» дня или исключить некоторую часть записей «текущего» дня.

Что вы должны делать:

Итак, нам нужен способ, который был бы безопасен для наших данных, и мы будем использовать индексы (если это возможно). Правильный путь имеет вид:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Учитывая, что есть только один месяц, @startOfPreviousMonth может быть легко заменен / получен с помощью:

DATEADD(month, -1, @startOCurrentfMonth)

Если вам нужно определить начало текущего месяца на сервере, вы можете сделать это следующим образом:

DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

Быстрое объяснение здесь. Начальный DATEDIFF(...) получит разницу между началом текущей эры (0001-01-01 - AD, CE, что угодно), по сути, возвращая большое целое число. Это количество месяцев до начала текущего месяца. Затем мы добавляем это число в начало эры, которая находится в начале данного месяца.

Таким образом, ваш полный сценарий может / должен выглядеть примерно так:

DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth) -- this was originally    misspelled
      AND date_created < @startOfCurrentMonth

Таким образом, все операции с датами выполняются только один раз, с одним значением; оптимизатор может свободно использовать индексы, и никакие неверные данные не будут включены.

12 голосов
/ 15 сентября 2009

Добавьте опции, которые были предоставлены до сих пор, не будут использовать ваши индексы вообще.

Что-то вроде этого поможет, и будет использовать индекс на столе (если он существует).

DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate
9 голосов
/ 20 апреля 2011
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET @EndDate = DATEADD(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

Обновление до решения mrdenny, таким образом, вы получите точно последний месяц с YYYY-MM-01

2 голосов
/ 15 сентября 2009

Один из способов сделать это - использовать функцию DATEPART :

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) = 4 
and DATEPART(year, date_created) = 2009

вернет все даты в апреле. За последний месяц (т. Е. До текущего месяца) вы также можете использовать GETDATE и DATEADD :

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) 
= (DATEPART(month, GETDATE()) - 1) and 
DATEPART(year, date_created) = DATEPART(year, DATEADD(m, -1, GETDATE()))
2 голосов
/ 12 декабря 2016

Прошлый месяц считается до последнего дня месяца. 31/01/2016 здесь последний день месяца будет 31 января, что не похоже на последние 30 дней.

SELECT CONVERT(DATE, DATEADD(DAY,-DAY(GETDATE()),GETDATE()))
2 голосов
/ 15 мая 2012
declare @PrevMonth as nvarchar(256)

SELECT @PrevMonth = DateName( month,DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)) + 
   '-' + substring(DateName( Year, getDate() ) ,3,4)
1 голос
/ 11 февраля 2018

SQL-запрос для получения записи только за текущий месяц

SELECT * FROM CUSTOMER
WHERE MONTH(DATE) = MONTH(CURRENT_TIMESTAMP) AND YEAR(DATE) = YEAR(CURRENT_TIMESTAMP);
1 голос
/ 15 октября 2017

Вы можете получить записи за последний месяц с этим запросом

SELECT * FROM dbo.member d 
WHERE  CONVERT(DATE, date_created,101)>=CONVERT(DATE,DATEADD(m, datediff(m, 0, current_timestamp)-1, 0)) 
and CONVERT(DATE, date_created,101) < CONVERT(DATE, DATEADD(m, datediff(m, 0, current_timestamp)-1, 0),101) 
1 голос
/ 15 августа 2017

Я из Oracle env, и я бы сделал это в Oracle:

select * from table
where trunc(somedatefield, 'MONTH') =
trunc(sysdate -INTERVAL '0-1' YEAR TO MONTH, 'MONTH')

Идея: я запускаю запланированный отчет за предыдущий месяц (с первого дня до последнего дня месяца, без окон). Это может быть неприемлемо для индексации, но в любом случае Oracle имеет быструю обработку дат. Есть ли подобный простой и короткий путь в MS SQL? Ответ, сравнивающий год и месяц по отдельности, кажется глупым людям Oracle.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...