Как обрабатывать переполнение компонента даты / времени для преобразования в DATETIME2? - PullRequest
1 голос
/ 26 апреля 2019

Предположим, у вас есть следующая ужасная структура данных в базе данных SQL Server для хранения даты и времени.

  • Год (int)
  • Месяц (int)
  • день (int)
  • час (int)
  • Минута (int)
  • секунда и миллисекунда (с плавающей точкой)

И вам нужно сохранить его, но создать вычисленный столбец DATETIME2 на его основе, и ваши данные в одном из ваших полей переполняют его реальную емкость (например, «Second and Millsecond» содержит 60 или более), и вы хотите преобразовать эти поля в DATETIME2; Как вы можете сделать это так, чтобы любые переполнения значений каскадно перешли на более высокий компонент даты / времени? Например, следующие недействительные данные DateTime будут преобразованы следующим образом:

  • 2018-01-01 10: 00: 60.111 ► 2018-01-01 10: 01: 00.111
  • 2018-12-31 23: 59: 61.123 ► 2019-01-01 00: 00: 01.123
  • 2018-01-01 10: 00: 120.000 ► 2018-01-01 10: 02: 00.000

В связи с моей конкретной проблемой, данные, которые я видел, переполняются только по секундам, а секунды должны составлять только 2 цифры, чтобы они не переполнялись более чем на 1 минуту, поэтому для этих данных будет достаточно только этого решения. Однако мне не нравится, что мы должны хранить эти поля int и float в нашей базе данных для хранения Date Times и, в конечном счете, хотели бы более пуленепробиваемые средства обработки любого типа переполнения (и недостаточного для полноты).

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

1 Ответ

1 голос
/ 26 апреля 2019

По сути, моя идея такова:

1, сначала использовать 0 в качестве секунд,

2, добавить секунды из SnM (секунды и миллисекунды)

3, добавитьМиллисекунды от SnM.

Будьте осторожны с проблемой преобразования типов данных ...

Попробуйте:

select 
dateadd(millisecond, cast(reverse(substring(reverse(cast(cast (SnM as decimal(10,3)) as varchar(50))),1,3)) as int),
dateadd(second, cast(substring(cast(cast (SnM as decimal(10,3)) as varchar(50)),1,charindex('.',cast(cast (SnM as decimal(10,3)) as varchar(50)))-1) as int), 
cast(concat(year,'-',month,'-',day,' ',hour,':',minute,':00') as datetime2))) as newdate
from test

Результат теста:

SQL <> Fiddle

...