2015-12-31 6 views
1

Я хочу получить последнюю дату последнего месяца (30 или 31) и время до последней секунды, когда запрос выполняется. Например. 11/30/2015 11:59:59 PMЧтобы получить последнюю дату предыдущего месяца до последней секунды

Так что у меня вопрос как

SELECT DATEADD(ss, (60*60*24)-1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), -1)) 

Это решает мою проблему. Но в чем разница между запросом, написанным выше и ниже, когда я изменяю часть DATEDIFF и заменяю 0 на 1?

SELECT DATEADD(ss, (60*60*24)-1, DATEADD(MONTH, DATEDIFF(MONTH, 1, GETDATE()), -1)) 

Будут ли оба эти запроса давать одинаковый результат всякий раз, когда они выполняются или которые я должен рассматривать как постоянное решение?

+0

Как уже отмечалось, это, вероятно, плохая идея - или вы * намереваетесь * исключить значение «2015-11-30T11: 59: 59.347'? –

ответ

0

См. Это link, как DATEDIFF используется или должен использоваться в SQL Server. Второй аргумент, который, по-видимому, не имеет значения в вашем случае, должен быть датой начала, которая вычитается из даты окончания (getdate()), чтобы получить разницу, а затем конвертироваться в месяцы. Я попытался бы использовать эту функцию как обычный способ и обеспечить правильную дату начала.

Также ниже альтернативный способ получения того же результата

SELECT DATEADD(ss, -1, '01/' + CONVERT(VARCHAR, DATEPART(MONTH, getdate())) + '/' + CONVERT(VARCHAR, DATEPART(YEAR, getdate()))); 
0

Это из-за DATEDIFF(MONTH, 0, GETDATE()) функции

Если используется целое число в качестве второго аргумента, это интерпретируется как число дней начиная с 1900-01-01 независимо от интервала, который вы используете в функции datediff.

Для например:

SELECT YEAR(0), MONTH(0), DAY(0); 
year month  day 

1900 1   1 

Теперь, если я Приращение от 0 до 1 в год, месяц, день

SELECT YEAR(1), MONTH(1), DAY(1); 
year month  day 

1900 1   2 

Теперь, если я Приращение значения 365,

SELECT YEAR(365), MONTH(365), DAY(365); 
year  month  day 

1901 1   1 

Вы можете увидеть год получил увеличивается на 1.

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

SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)) 
+0

Спасибо! Это хорошее объяснение. –

2

НЕ ДЕЛАЙТЕ это; попытаться получить «последнюю секунду» в последний день предыдущего месяца

я сделать это смелое заявление, исходя из предположения, вы пытаетесь использовать BETWEEN и вы обеспокоены тем, с точностью что-то вроде этого:

select sum(value) from Atable 
where [Adate] BETWEEN '20151201' AND '21051231 59:59:59' 

Но сложность прибытия в последний момент времени в последний день любого месяца решается так легко, используя вместо этого первый день следующего месяца. Все, что вам также нужно сделать, это отказаться от использования МЕЖДУ. Как это:

select sum(value) from Atable 
where [Adate] >= '20151201' and [Adate] < '21060101' 

МЕНЕЕ «первый день этого месяца»

Вот как вы решить головоломку.

&: Точность (точность) smalldatetime, datetime и datetime2 все отличается, тем более причина не использовать МЕЖДУ.

см "Будьте осторожны ошибок округления" в http://sqlmag.com/t-sql/t-sql-best-practices-part-2


В частности, это сделать:

DateLogged < ВЫБРАТЬ DATEADD (МЕСЯЦ, DATEDIFF (МЕСЯЦ, 0, GETDATE()) , 0)

Это будет на 100% точным для столбцов даты, smalldatetime, datetime и datetime2.


Вот еще одна попытка объяснить, почему МЕНЕЕ [the_next_day_at_00: 00: 00 + 0000000] является точным и использование 22:59:59 не является точным. Пожалуйста, обратите внимание точности данных выборки

SQL Fiddle

Сервер 2014 Настройка схемы MS SQL:

Запрос 1:

DECLARE @Tbl TABLE 
    ( [ID] int identity(1,1) 
    , [DT_a] datetime 
    , [DT_b] datetime 
    , [DT_c] datetime2 
    ) 

INSERT INTO @Tbl 
    ([Dt_a], [Dt_b], [Dt_c]) 
VALUES 
    (
     '20151231 23:59:59' 
    , '20151231 23:59:59.997' 
    , '20151231 23:59:59.9999999' 
    ) 

select 
     'where [DT_b] <= 20151231 23:59:59' as FilterString 
    , max([Dt_a]) as [Dt_a] 
    , max([Dt_b]) as [Dt_b] 
    , max([Dt_c]) as [Dt_c] 
from @Tbl 
where [DT_b] <= '20151231 23:59:59' 

UNION ALL 
select 
     'where [DT_b] < 20160101' 
    , max([Dt_a]) as [Dt_a] 
    , max([Dt_b]) as [Dt_b] 
    , max([Dt_c]) as [Dt_c] 
from @Tbl 
where [DT_b] < '20160101' 

Results:

|      FilterString |      Dt_a |      Dt_b |      Dt_c | 
|-----------------------------------|----------------------------|----------------------------|-----------------------------| 
| where [DT_b] <= 20151231 23:59:59 |      (null) |      (null) |      (null) | 
|   where [DT_b] < 20160101 | December, 31 2015 23:59:59 | December, 31 2015 23:59:59 | 2015-12-31 23:59:59.9999999 | 

точность данных

  • smalldatetime: одна минута
  • datetime: округляется до шагом .000, .003, или.007 секунд
  • datetime2: 100 наносекунд

Для того, чтобы избежать возможных ошибок округления от временных единиц НЕ ИСПОЛЬЗОВАТЬ < = 23:59:59

Вместо того, чтобы использовать менее [the_next_day]

И , как следствие, ИЗБЕГАЙТЕ ИСПОЛЬЗОВАТЬ МЕЖДУ МЕЖДУ на диапазоны дат.

+0

Если бы я мог это сделать не один раз, я бы это сделал. Это действительно хороший совет. –

+0

Я ценю ваш совет, но это не относится к моей проблеме. Мне нужно получить все данные, например. например: DateLogged <= SELECT DATEADD (ss, (60 * 60 * 24) -1, DATEADD (MONTH, DATEDADF (MONTH, 0, GETDATE()), -1)) , что означает все записи до последнего момента предыдущего дня предыдущего месяца. Также я не хочу никаких жестко закодированных дат. –

+0

Я не предлагаю жестко установленные даты, я пытаюсь заставить вас отказаться от равных (то есть меньше, чем только, не меньше или равно), как только вы это сделаете, ваша проблема станет еще легче решить. Я поправлю свой ответ, чтобы быть более конкретным, поскольку я явно не сумасшедший. –

Смежные вопросы