каков наилучший способ хранения временного интервала в базе данных SQL server

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

  • 1 час 3 минуты
  • 47 мин.
  • 10 часов
  • 3 минуты 14 секунд

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

5 ответов


Do не используйте типы символов для хранения информации о дате / времени.

в SQL Server 2008 у вас есть time типа для этого, что вы должны использовать, если ваш срок менее 1 дня. В предыдущих версиях, или если вам нужно хранить большие интервалы, вам придется использовать datetime или smalldatetime (в зависимости от точности необходимо).

другой вариант-выбрать единицу времени-скажем, минуты - и просто использовать int значение представляют количество единиц. Просто убедитесь, что (а) выбранная вами единица достаточно точна для записи наименьших интервалов, которые необходимо отслеживать, и (Б) фактический числовой тип достаточно велик, чтобы содержать наибольшие интервалы, которые необходимо отслеживать. А smallint может быть достаточно для отслеживания количества минут в течение дня; с другой стороны, отслеживание количества миллисекунд в течение 10-летнего периода должно храниться как bigint.


просто используйте integer для хранения интервала в секундах. функция datediff возвращает целое число. Напишите функцию, которая превратит его в текст. Этому нужны некоторые настройки (поэтому он показывает "1 мин", а не" 1 мин"), но должен работать нормально:

CREATE FUNCTION dbo.SecondsToText(@seconds int)
RETURNS VARCHAR(100)
AS
BEGIN
  declare @days int;
  set @days = @seconds/(3600 * 24);
  declare @hours int;
  set @hours = (@seconds - @days * 3600 * 24) / 3600;
  declare @minutes int;
  set @minutes = (@seconds - @days * 3600 * 24 - @hours * 3600) / 60;
  set @seconds = (@seconds - @days * 3600 * 24 - @hours * 3600 - @minutes * 60);
  RETURN 
    RTRIM(CASE WHEN @days > 0 THEN CAST(@days as varchar) + ' days ' ELSE '' END +
    CASE WHEN @hours > 0 THEN CAST(@hours as varchar) + ' hours ' ELSE '' END +
    CASE WHEN @minutes > 0 THEN CAST(@minutes as varchar) + ' minutes ' ELSE '' END + 
    CASE WHEN @seconds > 0 THEN CAST(@seconds as varchar) + ' seconds ' ELSE '' END)
END
GO

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

кроме того, SQL Server 2008 вводит новый TIME тип данных что позволяет хранить только значения времени.


Как сказал @Aaronaught, используйте тип данных date / time или datetime (при необходимости) для хранения ваших значений; но эти типы хранят только экземпляр во времени, а не промежуток времени или продолжительности. Вам нужно будет использовать два поля для хранения интервала, например [time_span_start] и [time_span_end]. Разница между ними даст вам интервал.

на более длинный ответ на ваш вопрос можно ответить, загрузив копию " разработка приложений баз данных, ориентированных на время в SQL " Ричарда т. Снодграсса. Он свободно доступен в формате PDF, посмотрите здесь:

http://www.cs.arizona.edu / ~rts/publications.html


связанный с ответом Тони, вы также можете использовать один столбец datetime относительно стандартного времени начала, которое неявно для всех интервалов - например: 1/1/1900 12: 00 AM.

В данном случае это достаточно легко для хранения:

INSERT INTO tbl (interval) VALUES (DATEADD(s, '1/1/1900', DATEDIFF(s, @starttime, @endtime))

Теперь это, очевидно, нелегко для выполнения сумм строк, поэтому вы можете подумать о добавлении сохраненных вычисляемых столбцов DATEDIFF(s, '1/1/1900', interval), чтобы предоставить секунды для выполнения сумм.

Теперь, вот где это становится интересным для SQL Server:

из-за реализации SQL Server для преобразования чисел в и из дат, 0 - > 1/1/1900 12:00 AM, 0.5 - > 1/1/1900 12:00 PM, 1 - > 1/2/1900 12:00 AM и т. д. т. е. целое число рассматривается как число дней с 1/1/1900 и дробная часть-доля в течение дня. Таким образом, вы можете наивно добавить их, чтобы получить интервал.

и на самом деле:

SELECT  CONVERT(DATETIME, 1) + CONVERT(DATETIME, 0) + CONVERT(DATETIME, 2) + CONVERT(DATETIME, 0.5)

дает 1900-01-04 12:00:00.000' как ожидалось

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

DECLARE @datetest TABLE ( dt DATETIME NOT NULL )

INSERT  INTO @datetest ( dt )
VALUES  ( 0 )
INSERT  INTO @datetest ( dt )
VALUES  ( 1 )
INSERT  INTO @datetest ( dt )
VALUES  ( 2 )
INSERT  INTO @datetest ( dt )
VALUES  ( 0.5 )

SELECT  *
FROM    @datetest

SELECT  CONVERT(DATETIME, SUM(CONVERT(FLOAT, dt)))
FROM    @datetest

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