Как мне остановить SQL Сервер, поменяв местами месяц и день? - PullRequest
3 голосов
/ 07 января 2020

У меня следующий запрос:

DECLARE @someDateTime DATETIME = '2019-12-01 00:00:00.000'; -- 1st December 2019
SELECT @someDateTime;

Результат

2019-01-12 00:00:00.000

Я ожидал, что результат будет 2019-12-01 00:00:00.000 (1 st *) 1011 * Декабрь 2019 г.) - Меняется месяц и дата по неизвестной причине.

До недавнего времени у меня никогда не было проблем с этим форматом.

Как мне ввести дату в формате "ГГГГ-ММ-ДД ЧЧ: мм: сс.000", и сохранить ли ее в том формате, который был присвоен переменной / отображен в выборке?
Какой параметр определяет этот формат, который мог измениться?

Потенциально полезная информация

dbcc useroptions

Результат:

Set Option | Value
----------   -----
...
language   | British
dateformat | dmy
...

Server Properties

То, что я пробовал:

Запрос 1

Изменение даты на что-то, что было бы недопустимым, если поменять местами

DECLARE @someDateTime DATETIME = '2019-12-20 00:00:00.000';
SELECT @someDateTime;

Результат:

Сообщение 242, Уровень 16, Состояние 3, Строка 4
Преобразование типа данных varchar в тип данных datetime привело к значению вне допустимого диапазона.

Запрос 2

Установка переменной после ее объявления

DECLARE @someDateTime DATETIME;
SET @someDateTime = '2019-12-01 00:00:00.000';
SELECT @someDateTime;

Результат - НЕОБХОДИМЫЙ:

2019-01-12 00:00:00.000

Запрос 3

Вставка переменной в табличную переменную

DECLARE @someDateTime DATETIME = '2019-12-01 00:00:00.000';
DECLARE @someTable TABLE (someDateTimeColumn DATETIME);
INSERT @someTable VALUES (@someDateTime);
SELECT * FROM @someTable

Результат - НЕОБХОДИМО:

someDateTimeColumn
------------------
2019-01-12 00:00:00.000

Запрос 4

Вставка данных непосредственно в переменную таблицы ble

DECLARE @someTable TABLE (someDateTimeColumn DATETIME);
INSERT @someTable VALUES ('2019-12-01 00:00:00.000');
SELECT * FROM @someTable

Результат: UNDESIRED

someDateTimeColumn
------------------
2019-01-12 00:00:00.000

Запрос 5

Изменение формата введенной строки

DECLARE @someDateTime DATETIME = '01/12/2019';
SELECT @someDateTime;

Результат - DESIRED

2019-12-01 00:00:00.000

Запрос 6

Изменение формата введенной строки

DECLARE @someDateTime DATETIME = '2019-12-01T00:00:00.00';
SELECT @someDateTime;

Результат - Желаемый:

2019-12-01 00:00:00.000

Запрос 7

Изменение формата введенной строки

DECLARE @someDateTime DATETIME = '2019-12-01';
SELECT @someDateTime;

Результат - НЕОБХОДИМО:

2019-01-12 00:00:00.000

Запрос 8

Использование SET DATEFORMAT

SET DATEFORMAT ymd
DECLARE @someDateTime DATETIME = '2019-12-01';
SELECT @someDateTime;

Результат - желаемый

2019-12-01 00:00:00.000

Ответы [ 3 ]

4 голосов
/ 07 января 2020

Вы можете использовать буквальный формат YYYYMMDD, который всегда интерпретируется как год-месяц-день, независимо от языковых настроек вашего SQL Сервера:

DECLARE @someDateTime DATETIME = '20191201 00:00:00.000';
3 голосов
/ 07 января 2020

Одно решение - использовать полный формат ISO8601, ie 2019-12-01T00:00:00.000, другое - использовать неразделенный формат даты, ie 20191201 00:00:00.000. Однако лучшим решением было бы переключиться на datetime2.

datetime2, которое было введено через 15 (или было 11) лет за go, чтобы избавиться от причуд datetime, таких как миллисекунда неточность, произвольная точность, странная арифметика c и ... разбор идиосинкразий. Например, парсинг datetime2 формата ISO8601 не зависит от DATEFORMAT:

SET DATEFORMAT ydm
DECLARE @someDateTime DATETIME2(0) = '2019-12-01 00:00:00.000'
select @someDateTime
------
2019-12-01 00:00:00

Это защищает ваш код от неудачных изменений настроек сервера

0 голосов
/ 07 января 2020

Прочитав эту статью из комментария @ SMor, комментарий, сделанный моим коллегой из поиска в Google, и вспомнив кое-что, что я сделал несколько месяцев в go, я думаю, что понял, что происходит и что изменилось.

Мой пользователь БД по умолчанию был настроен на:

language   | us_english
dateformat | mdy

Поэтому при чтении строки '2019-12-01' SQL Сервер ожидал mm-dd-yyyy.

SQL сервер умный, хотя. Он видит первую часть 2019 и понимает, что это на самом деле год, поэтому он сдвигает год к концу, а затем пытается снова. *

Теперь у него есть 12-01-2019, который соответствует ожидаемому формату.

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

Я выбрал British.

Мой пользователь БД сейчас установите на:

language   | British
dateformat | dmy

Таким образом, при чтении строки '2019-12-01' SQL Сервер ожидает dd-mm-yyyy.

После смещения года он становится 12-01-2019, который он интерпретирует как dd-mm-yyyy оставив меня с 12 января th 2019 вместо 1 декабря st 2019

Сегодня был длинный день.

* Обратите внимание, это довольно упрощенное объяснение того, как я выдержать этот вопрос Возможно, это не то, как оно на самом деле функционирует, но работает, чтобы удовлетворить мое любопытство по этому вопросу.

...