Месяц в дате в SQL Server 2008 - PullRequest
2 голосов
/ 16 ноября 2011

Надеюсь, это будет легко ответить.

Я работаю над таблицей, требующей данных MTD. Один из наших парней SQL сказал мне использовать

MONTH (@monthtodate)= 11

Где @monthtodate установлено в GetDate() в списке параметров в SQL Server Management Studio. Таким образом, в «теории» он говорит, что нужно выбрать месяц (11), а затем получить сегодня и вернуть все запрошенные данные между этими двумя датами. Но я думаю, что это не правильно.

Глядя на мои данные, я начинаю думать, что он просто возвращает данные за весь ноябрь, а не только MTD. Я думаю, технически, все, что имеет 0, не будет вычислено. Однако это просто означает, что он плохо написан, правильный код?

По вашему мнению, это был бы лучший способ вернуть данные MTD:

production_date <= @today and Production_Date >= DATEADD(mm, DATEDIFF(mm, 0, @today), 0)

Заранее всем спасибо!

Ответы [ 2 ]

2 голосов
/ 16 ноября 2011

Вот как я это делаю. Это должно работать практически на любой версии SQL Server.

Одна важная вещь, на которую следует обратить внимание: вначале всегда следует устанавливать одно значение, представляющее «сейчас», текущий момент времени. Если в вашем запросе пока нет согласованного значения, вы в конечном итоге получите бит, когда ваш запрос будет выполнен так, что он пересекает границу даты во время полета. Нет ничего лучше, чем выставлять счета кому-то за то, за что они уже заплатили в прошлом месяце. Наихудшие, подобные крайним, ошибки трудно уловить ни разработчикам, ни QA, поскольку ни одна из них, вероятно, не будет работать, скажем, в 11:59 31 декабря.

Код:

declare
  @dtNow  datetime ,
  @Today  datetime ,
  @dtFrom datetime ,
  @dtThru datetime

---------------------------------------------------------------------------------------
-- set our effective notion of 'now'-ness.
--
-- We need have a consistent notion of now, lest we get bit in the a$$
-- by an edge case where we cross a day/month/year boundary in mid-execution.
--
-- NOTE: Mostly, we're interested in the *DATE* rather than the actual moment-in-time.
--       So, we carry around two flavors here.
---------------------------------------------------------------------------------------
set @dtNow = current_timestamp
set @Today = convert(datetime,convert(varchar,@dtNow,112),112)

---------------------------------------------------------------------------------------
-- compute the current date.
--
-- 1. get the current date sans timestamp (effectively start-of-day)
-- 2. add 1 day, then back off 3 millseconds to set it to the last tick of the current day
--
-- NOTE: Depending on the requirements of your particular application (and the nature
--       of your data), you might want to use the actual current date/time value as
--       your upper bound.
--
-- FURTHER NOTE: How far to back off is dependent on your date/time type:
--
-- * For DateTime, the resolution is milliseconds and the last tick of the day
--   is 997 milliseconds, so you need to back off 3ms from the start of the
--   next day.
--
-- * SmallDateTime has a 1 second resolution. The last tick of the day, natch,
--   is 59 seconds, so you need to back off 1 second from the start of the next day.
--
-- * For DateTime2, the user declares the precision in decimal fractions of a second,
--   though its resolution is 100ns ticks. You'll need (especially if you're working
--   with DateTime2 columns/variables of differing precision) experiment to figure out
--   what traps Microsoft has set for you inside DateTime2 and what you need to do to
--   make things work properly.
--
---------------------------------------------------------------------------------------
set @dtThru = dateadd(ms,-3,dateadd(day,1,@Today))
--set @dtThru = @dtNow -- if you need the actual current date/time value

---------------------------------------------------------------------------------------
-- compute start of month
--
-- We do this by subtracting the day number of 'today' from the date/time value @today.
-- That gives us the last day of the prior month. Then we add one day to get the first
-- day of the current month.
---------------------------------------------------------------------------------------
set @dtFrom = dateadd(day,1-day(@Today),@Today)

---------------------------------------------------------------------------------------
-- finally, make your query for 'current month to date'
---------------------------------------------------------------------------------------
select *
from dbo.foobar t
where t.recorded_date between @dtFrom and @dtThru
0 голосов
/ 16 ноября 2011

Если вы спросите, какой из этих двух запросов лучше с точки зрения производительности:

DECLARE @now datetime = GETDATE()

SELECT * 
FROM yourTable 
WHERE Production_Date >= DATEADD(mm, DATEDIFF(mm, 0, @now), 0)
AND Production_Date < @now

SELECT * 
FROM yourTable 
WHERE YEAR(Production_Date) = YEAR(@now)
AND MONTH(Production_Date) = MONTH(@now)
AND Production_Date < @now

Тогда будет первый, поскольку он будет использовать индекс для Production_Date, если он есть.Однако они оба должны возвращать одинаковые результаты.

...