MSSQL, округление до 10 минут
От: Anton Batenev Россия https://github.com/abbat
Дата: 14.08.06 03:45
Оценка:
Hello, All!

Требуется произвольное значение типа datetime округлить до дня, часа, 10 минут, минуты, отбросив остаток. Например

для значения
01.01.2001 10:11:10.100

округление до дня:       01.01.2001 00:00:00.000
округление до часа:      01.01.2001 10:00:00.000
округление до 10 минут:  01.01.2001 10:10:00.000
округление до минуты:    01.01.2001 10:11:00.000


Понятно, что тип datetime хранится как 8-и байтовый float, где целая часть — это количество дней с 1900 года. Но вот, что меня смущает:

SET DATEFORMAT DMY
DECLARE @d DATETIME
SET @d = '01.01.2001 10:10:00.000'
SELECT @d, CAST(CAST(@d AS FLOAT) AS DATETIME)


Результат:

+-------------------------+--------------------------+
| 2001-01-01 10:10:00.000 | 2001-01-01 10:09:59.997 |
+-------------------------+--------------------------+


1. Чего я неправильно понимаю? Ведь каст между одним и тем же типом не должен приводить к смене значения?
2. Как все же сделать окургление наиболее правильно, при условии, что функция будет использоваться достаточно интенсивно и в больших запросах, и конвертация в символьное представление мне как-то не особо нравится.
Folding@Home on TSC! Russia
Re: MSSQL, округление до 10 минут
От: DarkSid Россия  
Дата: 14.08.06 07:25
Оценка: 6 (1)
Здравствуйте, Anton Batenev, Вы писали:

AB>Hello, All!


AB>Требуется произвольное значение типа datetime округлить до дня, часа, 10 минут, минуты, отбросив остаток. Например


AB>
AB>для значения
AB>01.01.2001 10:11:10.100

AB>округление до дня:       01.01.2001 00:00:00.000
AB>округление до часа:      01.01.2001 10:00:00.000
AB>округление до 10 минут:  01.01.2001 10:10:00.000
AB>округление до минуты:    01.01.2001 10:11:00.000
AB>


AB>Понятно, что тип datetime хранится как 8-и байтовый float, где целая часть — это количество дней с 1900 года. Но вот, что меня смущает:


AB>
AB>SET DATEFORMAT DMY
AB>DECLARE @d DATETIME
AB>SET @d = '01.01.2001 10:10:00.000'
AB>SELECT @d, CAST(CAST(@d AS FLOAT) AS DATETIME)
AB>


AB>Результат:


AB>
AB>+-------------------------+--------------------------+
AB>| 2001-01-01 10:10:00.000 | 2001-01-01 10:09:59.997 |
AB>+-------------------------+--------------------------+
AB>


AB>1. Чего я неправильно понимаю? Ведь каст между одним и тем же типом не должен приводить к смене значения?

AB>2. Как все же сделать окургление наиболее правильно, при условии, что функция будет использоваться достаточно интенсивно и в больших запросах, и конвертация в символьное представление мне как-то не особо нравится.



?
-- 0 — округлить до дня
-- 1 — округлить до часа
-- 2 — округлить до 10 минут
-- 3 — округлить до минуту

select case @Format
when 0 then dateAdd(hh,-1*DATEPART(hh, @DateTime),dateAdd(mi,-1*DATEPART(mi, @DateTime),dateAdd(ss,-1*DATEPART(ss, @DateTime),dateAdd(ms,-1*DATEPART(ms, @DateTime),@DateTime))))
when 1 then dateAdd(mi,-1*DATEPART(mi, @DateTime),dateAdd(ss,-1*DATEPART(ss, @DateTime),dateAdd(ms,-1*DATEPART(ms, @DateTime),@DateTime)))
when 2 then dateAdd(mi,-1*(DATEPART(mi, @DateTime) — round(DATEPART(mi, @DateTime)-5,-1)),dateAdd(ss,-1*DATEPART(ss, @DateTime),dateAdd(ms,-1*DATEPART(ms, @DateTime),@DateTime)))
when 3 then dateAdd(ss,-1*DATEPART(ss, @DateTime),dateAdd(ms,-1*DATEPART(ms, @DateTime),@DateTime))
end

И оформит как пользовательскую функцию
Re: MSSQL, округление до 10 минут
От: ZAMUNDA Земля для жалоб и предложений
Дата: 15.08.06 08:30
Оценка:
Здравствуйте, Anton Batenev, Вы писали:

AB>Hello, All!


AB>Требуется произвольное значение типа datetime округлить до дня, часа, 10 минут, минуты, отбросив остаток.



AB>Понятно, что тип datetime хранится как 8-и байтовый float, где целая часть — это количество дней с 1900 года. Но вот, что меня смущает:

Неа он не так храниЦЦа.

Values with the datetime data type are stored internally by Microsoft SQL Server as two 4-byte integers. The first 4 bytes store the number of days before or after the base date, January 1, 1900. The base date is the system reference date. Values for datetime earlier than January 1, 1753, are not permitted. The other 4 bytes store the time of day represented as the number of milliseconds after midnight.

Это 'variant time' тип так хранит дату.

AB> <skip>


AB>1. Чего я неправильно понимаю? Ведь каст между одним и тем же типом не должен приводить к смене значения?

То что ты неправильно понимаешь, я тебе уже сказал. Глюк происходит из-за погрешностей при конвертации в число с плавающей точкой и обратно.
И когда делаешь CAST(... AS FLOAT) то MSSQL это на CONVERT заменяет (по крайней мере в Execution plan'е).

AB>2. Как все же сделать окургление наиболее правильно, при условии, что функция будет использоваться достаточно интенсивно и в больших запросах, и конвертация в символьное представление мне как-то не особо нравится.

CONVERT'ом CAST'ом и ROUND'ом.
DECLARE @Date AS DateTime

SET @Date = GETDATE()

SELECT    CONVERT(DateTime, 
            LEFT(CONVERT(VARCHAR, @Date, 120), 14) + 
            CAST(ROUND(DATEPART(mi, @Date) + DATEPART(s, @Date)/60, -1) AS VARCHAR) + 
            ':00', 
        120)
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.