代码之家  ›  专栏  ›  技术社区  ›  Josh Stodola

在T-SQL中使用DATEDIFF

  •  6
  • Josh Stodola  · 技术社区  · 16 年前

    我正在SQL语句中使用DATEDIFF。我正在选择它,我还需要在WHERE子句中使用它。这个声明不起作用。。。

    SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable
    WHERE InitialSave <= 10
    

    无效的列名“InitialSave”

    但这句话很好用。。。

    SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable
    WHERE DATEDIFF(ss, BegTime, EndTime) <= 10
    

    我的程序员说这是低效的(好像我调用了两次函数)。

    所以有两个问题。为什么第一个语句不起作用?使用第二个语句是否效率低下?

    5 回复  |  直到 16 年前
        1
  •  7
  •   momo    12 年前

    当我最初写这个答案的时候,我说其中一列上的索引可以创建一个比其他答案性能更好的查询(并提到Dan Fuller的)。然而,我的想法并不是100%正确。事实是,如果没有计算列或索引(物化)视图,将需要进行完整的表扫描 必修的 相同的 桌子

    创造条件

    我所指的最佳实践是将一列移动到比较运算符的一侧,如下所示:

    SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
    FROM dbo.MyTable T
    WHERE T.EndTime <= T.BegTime + '00:00:10'
    

    SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
    FROM
       dbo.BeginTime B
       INNER JOIN dbo.EndTime E
          ON B.BeginTime <= E.EndTime
          AND B.BeginTime + '00:00:10' > E.EndTime
    

    EndTime 在这两种情况下,现在仅在比较的一方。假设 BeginTime 表中的行要少得多,而 结束时间 结束时间 ,这将比使用 DateDiff(second, B.BeginTime, E.EndTime) . 现在是 萨尔盖博 扫描 这个 开始时间 桌子,它可以 寻找 进入 桌子需要仔细选择哪一列单独位于操作符的一侧——通过放置 开始时间 通过自己做一些代数来切换到 AND B.BeginTime > E.EndTime - '00:00:10'

    我还要指出 DateDiff 不回来 逝去 时间,而不是计算 边界 交叉的。如果打电话给 DateDiff 使用秒返回 1 ,这可能意味着 3 ms 经过的时间,或者它可能意味着 1997 ms ! 这本质上是+-1时间单位的精度。为了获得更高的+-1/2时间单位精度,您需要以下查询比较 0 EndTime - BegTime :

    SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
    FROM MyTable
    WHERE EndTime <= BegTime + '00:00:10'
    

    datetime 数据类型——减去 date time 必须转换为的值 日期时间 或者使用其他方法获得更好的精度(大量 DateAdd , DateDiff

    这一原则在计算较大的单位(如小时、天或月)时尤为重要。A. DateDiff 属于 1 month 可能相隔62天(想想2013年7月1日-2013年8月31日)!

        2
  •  5
  •   Dan Fuller    16 年前

    但是你可以这样做

    select InitialSave from 
    (SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable) aTable
    WHERE InitialSave <= 10
    

    作为旁注,这实际上是将DATEDIFF移动到where语句中,以确定它的第一个定义位置。在where语句中的列上使用函数会导致索引的使用效率降低,如果可能的话应该避免使用,但是如果必须使用datediff,那么就必须这样做!

        3
  •  3
  •   KM.    16 年前

    除了使其“工作”,还需要使用索引

    使用带索引的计算列或带索引的视图,否则将进行表扫描。当你排得足够多时,你会感到 疼痛 慢扫描!

    ALTER TABLE MyTable ADD
        ComputedDate  AS DATEDIFF(ss,BegTime, EndTime)
    GO
    CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate  ON MyTable 
        (
        ComputedDate
        ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    GO
    

    创建视图&索引:

    CREATE VIEW YourNewView
    AS
    SELECT
        KeyValues
            ,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
        FROM MyTable
    GO
    CREATE CLUSTERED INDEX IX_YourNewView
        ON YourNewView(InitialSave)
    GO
    
        4
  •  2
  •   Otávio Décio    16 年前

    您必须使用函数而不是列别名-与count(*)等PITA相同。

        5
  •  1
  •   gts    16 年前

    作为替代,您可以使用 computed columns .