Как я могу усечь datetime в SQL Server?

каков наилучший способ усечения значения datetime (для удаления часов минут и секунд) в SQL Server 2008?

например:

declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)

-----------------------
2009-05-28 00:00:00.000

13 ответов


Это продолжает часто собирать дополнительные голоса, даже несколько лет спустя, и поэтому мне нужно обновить его для современных версий Sql Server. Для Sql Server 2008 и более поздних версий это просто:

cast(getDate() As Date)

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

но есть и другие способы сделать это. Вот самые общий.

правильный способ (новый с Sql Server 2008):

cast(getdate() As Date)

правильный путь (старый):

dateadd(dd, datediff(dd,0, getDate()), 0)

теперь это старше, но это все еще стоит знать, потому что он также может легко адаптироваться к другим временным точкам, таким как первый момент месяца, минуты, часа или года.

этот правильный способ использует документированные функции, которые являются частью стандарта ansi и гарантированно работают, но это может быть несколько замедлившийся. Он работает, находя, сколько дней есть от дня 0 до текущего дня, и добавляя, что много дней назад в день 0. Он будет работать независимо от того, как хранится ваше datetime и независимо от вашей локали.

быстрый способ:

cast(floor(cast(getdate() as float)) as datetime)

это работает, потому что столбцы datetime хранятся в виде 8-байтовых двоичных значений. Приведите их к плаванию, выровняйте их, чтобы удалить дробь, и временная часть значений исчезнет, когда вы вернете их в datetime. Это все просто немного сдвигается без сложной логики, и это очень быстро.

имейте в виду, что это зависит от детали реализации Microsoft может свободно меняться в любое время, даже в автоматическом обновлении службы. Это не очень портативный. На практике очень маловероятно, что эта реализация изменится в ближайшее время, но все равно важно осознавать опасность, если вы решите ее использовать. И теперь, когда у нас есть возможность выбрать дату, это редко необходимый.

неправильно:

cast(convert(char(11), getdate(), 113) as datetime)

неправильный способ работает путем преобразования в строку, усечения строки и преобразования обратно в datetime. Это неправильно, по двум причинам: 1)это может не работать во всех локалях и 2) это о самом медленном возможном способе сделать это... и не просто мало, это все равно на порядок или два медленнее, чем другие варианты.


обновление это было в последнее время я получаю несколько голосов, и поэтому я хочу добавить к нему, что с тех пор, как я опубликовал это, я видел довольно веские доказательства того, что Sql Server оптимизирует разницу в производительности между "правильным" способом и "быстрым" способом, то есть теперь вы должны поддержать первый.

в любом случае, вы хотите пишите ваши запросы, чтобы избежать необходимости делать это в первую очередь. Очень редко вы должны делать эту работу над базой данных.

в большинстве мест база данных уже является вашим узким местом. Это, как правило, сервер, который является самым дорогим для добавления оборудования для повышения производительности и труднее всего получить эти дополнения правильно (вы должны сбалансировать диски с памятью, например). Это также труднее всего масштабировать наружу, как технически, так и с точки зрения бизнеса; гораздо проще технически добавить веб-сервер или сервер приложений, чем сервер баз данных, и даже если это было ложно, вы не платите $20,000+ за серверную лицензию для IIS или апаш.

Я пытаюсь сказать, что, когда это возможно, вы должны делать эту работу на уровне приложения. The только время, когда вы должны когда-либо найти усечение datetime на Sql Server, когда вам нужно группировать по дням, и даже тогда вы, вероятно, должны иметь дополнительный столбец, настроенный как вычисляемый столбец, поддерживаемый во время вставки/обновления или поддерживаемый в логике приложения. Получите эту индексную, cpu-тяжелую работу с вашей базой данных.


только для SQL Server 2008

CAST(@SomeDateTime AS Date) 

затем верните его в datetime, если хотите

CAST(CAST(@SomeDateTime AS Date) As datetime)

просто ради более полного ответа, вот рабочий способ для усечения любой из частей даты вниз и включая минуты (заменить GETDATE() С датой для усечения).

это отличается от принятого ответа тем, что вы можете использовать не только dd (дней), но любой из частей даты (см. здесь):

dateadd(minute, datediff(minute, 0, GETDATE()), 0)

обратите внимание, что в приведенном выше выражении 0 - постоянная дата начала года (1900-01-01). Если нужно усечение на меньшие части, такие как секунды или миллисекунды, вам нужно взять постоянную дату, которая ближе к дате усечения, чтобы избежать переполнения.


фрагмент, который я нашел в интернете, когда мне пришлось это сделать, был:

 dateadd(dd,0, datediff(dd,0, YOURDATE))
 e.g.
 dateadd(dd,0, datediff(dd,0, getDate()))

В SQl 2005 ваша функция trunc_date может быть записана следующим образом.

(1)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
    CAST(FLOOR( CAST( @date AS FLOAT ) )AS DATETIME)
END

первый метод намного чище. Он использует только 3 вызова методов, включая final CAST () и не выполняет конкатенацию строк, что является автоматическим плюсом. Кроме того, здесь нет огромных слепков. Если вы можете себе представить, что метки даты/времени могут быть представлены, то преобразование из дат в числа и обратно в даты довольно легко процесс.

(2)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
      SELECT CONVERT(varchar, @date,112)
END

Если вы обеспокоены реализацией microsoft datetimes (2) или (3) может быть в порядке.

(3)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
SELECT CAST((STR( YEAR( @date ) ) + '/' +STR( MONTH( @date ) ) + '/' +STR( DAY(@date ) )
) AS DATETIME
END

В-третьих, более трудоемкий метод. Это требует разбивки даты на год, месяц и День, объединения их в формате "гггг/ММ/ДД", а затем возврата к дате. Этот метод включает в себя 7 вызовов методов, включая final CAST (), не говоря уже о конкатенации строк.


CONVERT(DATE, <yourdatetime>) or CONVERT(DATE, GetDate()) or CONVERT(DATE, CURRENT_TIMESTAMP)

выберите литая(пол(литой(функции getdate() как поплавок)) как datetime) Ссылка на это: http://microsoftmiles.blogspot.com/2006/11/remove-time-from-datetime-in-sql-server.html


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

SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) + (FLOOR((CAST(GETDATE() AS FLOAT) - FLOOR(CAST(GETDATE() AS FLOAT))) * 1440.0) + (3.0/86400000.0)) / 1440.0 AS DATETIME)

так если бы сегодня был 2010-11-26 14:54:43.123 тогда это вернется 2010-11-26 14:54:00.000.

изменить интервал его trucates, чтобы заменить 1440.0 с количеством интервалов в день, например:

24hrs          =   24.0  (for every hour)
24hrs / 0.5hrs =   48.0  (for every half hour)
24hrs / (1/60) = 1440.0  (for every minute)

(всегда ставлю .0 в конце, чтобы неявно привести к плыть.)


для тех из вас интересно, что (3.0/86400000) в моих расчетах SQL Server 2005, похоже, не отбрасывается из FLOAT to DATETIME точно, так что это добавляет 3 миллисекунды перед напольным покрытием.


этот запрос должен дать вам результат, эквивалентный trunc(sysdate) в Oracle.

SELECT  * 
FROM    your_table
WHERE   CONVERT(varchar(12), your_column_name, 101)
      = CONVERT(varchar(12), GETDATE(), 101)

надеюсь, что это помогает!


вы также можете извлечь дату using Substring из переменной datetime и возврат к datetime будет игнорировать часть времени.

declare @SomeDate datetime = '2009-05-28 16:30:22'
SELECT cast(substring(convert(varchar(12),@SomeDate,111),0,12) as Datetime) 

кроме того, вы можете получить доступ к частям переменной datetime и объединить их в усеченную дату конструкции, что-то вроде этого:

SELECT cast(DATENAME(year, @Somedate) + '-' + 
       Convert(varchar(2),DATEPART(month, @Somedate)) + '-' +
       DATENAME(day, @Somedate) 
       as datetime)

Oracle:

TRUNC(SYSDATE, 'MONTH')

SQL Server:

DATEADD(DAY, - DATEPART(DAY, DateField) + 1, DateField)

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


вы можете просто сделать это (SQL 2008):

объявить @SomeDate date = getdate ()

select @SomeDate

2009-05-28


TRUNC (aDate, 'DD') усечет min, sec и hrs

SRC:http://www.techonthenet.com/oracle/functions/trunc_date.php