Как SQL Server определяет стиль для преобразования, если он не указан? - PullRequest
5 голосов
/ 03 сентября 2010

Обновление: это ошибка, но не будет исправлена ​​до следующего выпуска SQL Server из-за проблем обратной совместимости.

с на этот вопрос , на который я ответил, но все еще озадачен.

Добавление TOP (1) к запросу достаточно, чтобы изменить результат с "3 сентября 2010" на "2010-09-03"(по крайней мере, на моей машине с британскими настройками) кто-нибудь может объяснить почему?Это ошибка или она где-то задокументирована?

Примечание: я также обнаружил, что если я использовал таблицу #temp, то оба запроса возвращали 2010-09-03

USE tempdb

BEGIN TRAN

CREATE TABLE t (d DATETIME NOT NULL)
INSERT INTO t VALUES (GETDATE())

SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '')
FROM t
/*
Returns "Sep  3 2010"

[Expr1004] = Scalar Operator(CONVERT(varchar(50),
                                     CONVERT(date,[tempdb].[dbo].[t].[d],0),
                                     0)+
                             CONVERT(varchar(50),[@1],0))
*/

SELECT TOP 1 (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '')
FROM t
/*
[Expr1004] = Scalar Operator(CONVERT(varchar(50),
                                     CONVERT(date,[tempdb].[dbo].[t].[d],0),
                                     121)+
                             '')
Returns "2010-09-03"
*/

ROLLBACK

Ответы [ 4 ]

6 голосов
/ 07 сентября 2010

Кажется, что за несогласованность виновата автопараметризация.

Books Online документы , которые DATE, TIME, DATETIME2 и DATETIMEOFFSET используют стиль 121 CONVERT по умолчанию, тогда как стиль 0 используется для DATETIME и SMALLDATETIME. Кто-то забыл обновить правила автопараметризации для новых типов:)

Если запрос может быть автоматически параметризован, стиль 0 ошибочно применяется к новым типам ДАТА / ВРЕМЯ, если имеет место неявное преобразование или явное преобразование без указанного стиля. Запрос без TOP автоматически параметризуется (вместо литерала TIME появляется параметр [@ 1]). TOP - это одна из (многих) функций запросов, которая предотвращает автоматическую параметризацию.

Очевидный обходной путь - всегда указывать нужный стиль при использовании CONVERT.

1 голос
/ 04 сентября 2010

Я могу воспроизвести, SQL 2008 R2 x64.

TOP (n), DISTINCT, GROUP BY, и функции управления окнами создают дату ГГГГ-ММ-ДД.ORDER BY нет.

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

--------------------------------  
-- these return Sep  4 2010
--------------------------------  
SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t
SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t ORDER BY 1 ASC
SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t ORDER BY 1 DESC

--------------------------------  
-- these return 2010-09-04
--------------------------------  
-- GROUP BY
SELECT c FROM (SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t) t (c) GROUP BY c
-- DISTINCT 
SELECT DISTINCT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t
-- TOP (n)
SELECT TOP (5) (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t
-- COUNT(*) OVER ()
SELECT COUNT(*) OVER (), (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t
-- ROW_NUMBER() OVER ()
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)), (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '') FROM t
1 голос
/ 06 сентября 2010

Это похоже на ошибку;Я могу воспроизвести на 2008 x64 Developer.

Я обнаружил нечто довольно странное;добавление другой даты (или даты / времени) к приведению varchar к запросу приводит к нормализации форматов.Итак:

USE tempdb

BEGIN TRAN

declare @d date = getdate()

CREATE TABLE t (d DATETIME NOT NULL)
INSERT INTO t VALUES (GETDATE())

SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '')
,(CONVERT(VARCHAR(50),@d))
FROM t


SELECT TOP 1 (CONVERT(VARCHAR(50),CONVERT(DATE, d))) + CONVERT(VARCHAR(50), '')
,(CONVERT(VARCHAR(50),@d))
FROM t

ROLLBACK

(обратите внимание на добавление преобразованной переменной @d к обоим запросам):

2010-09-06  2010-09-06
2010-09-06  2010-09-06

в качестве вывода.

Формат 121 выглядитскрытый формат по умолчанию для DATE, тогда как 0 является скрытым форматом по умолчанию для DATETIME.Я задавался вопросом, вызвана ли проблема первым запросом, игнорирующим самый внутренний CONVERT, или применяя его не по порядку?

1 голос
/ 03 сентября 2010

странно. я скопировал код yoru, удалил комментарии и удалил дополнение к дате, и это хорошо для них обоих.

    BEGIN TRAN 

CREATE TABLE t (d DATETIME NOT NULL) 
INSERT INTO t VALUES (GETDATE()) 

SELECT (CONVERT(VARCHAR(50),CONVERT(DATE, d)))
FROM t 


SELECT TOP 1 (CONVERT(VARCHAR(50),CONVERT(DATE, d)))
FROM t 

ROLLBACK 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...