代码之家  ›  专栏  ›  技术社区  ›  Martin Smith

在未指定转换样式时,SQL Server如何确定转换样式?

  •  5
  • Martin Smith  · 技术社区  · 14 年前

    更新:这是一个bug但是 won't get fixed until the next release of SQL Server due to backward compatibility concerns.

    以下是 this question 我回答了,但仍然感到困惑。

    添加 TOP (1)

    注:我在下面也发现如果我使用 #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 回复  |  直到 7 年前
        1
  •  6
  •   user440595 user440595    14 年前

    似乎自动参数化是造成不一致的原因。

    在线图书 documents

    在可以自动参数化查询的情况下,如果发生隐式转换或没有指定样式的显式转换,则样式0会错误地应用于新的日期/时间类型。没有TOP的查询是自动参数化的(显示参数[@1]而不是时间文本)。TOP是阻止自动参数化的(许多)查询特性之一。

        2
  •  1
  •   DForck42    14 年前

    奇怪的。我复制了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 
    
        3
  •  1
  •   Peter Radocchia    14 年前

    我可以复制,SQL 2008 R2 x64。

    TOP (n) , DISTINCT , GROUP BY ORDER BY

    因此,我猜它与tempdb中的spools、内部表示和本地化表示以及应该发生的自动来回切换有关,但在这种情况下不可能。

    --------------------------------  
    -- 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
    
        4
  •  1
  •   Ed Harper    14 年前

    这看起来像一个bug;我可以在2008 x64开发人员上重现。

    我确实发现了一些非常奇怪的事情;将另一个日期(或datetime)添加到varchar cast到查询中会导致格式标准化。所以:

    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 ,还是应用不当?