【问题标题】:SQL- Calculating average of differences between timesSQL-计算时间差的平均值
【发布时间】:2018-05-22 19:07:44
【问题描述】:

我有一个 sql 表,其中包含所有客户端的事务历史记录。我想找出两个事务之间的平均时间差是多少。

ClientCode      Date
DL2xxx          2016-04-18 00:00:00.000
DL2xxx          2016-04-18 00:00:00.000
E19xxx          2016-04-18 00:00:00.000
E19xxx          2016-04-18 00:00:00.000
E19xxx          2016-04-18 00:00:00.000
JDZxxx          2016-04-18 00:00:00.000

上面给出的是表格的前几行,给出的日期是交易发生的日期。我想取连续交易发生天数的平均差异。假设客户进行了第 1 天、第 3 天、第 10 天和第 15 天的交易。因此差异是 {2, 7, 5} 的平均值,平均为 4.66。如果只发生一个事务,则该值应为 0。

ClientCode AverageDays
DL2xxx     <float_value>
DL2xxx     <float_value>
E19xxx     <float_value>

这是每个唯一客户端代码只出现一次的输出应该是这样的。

【问题讨论】:

  • 你添加样本输出和输入数据
  • 我已经添加了更多细节,如果你觉得这不够,请通知我。
  • 如果性能是一个问题,您能否提供有关表上有哪些索引的信息?
  • 什么是索引?此表中没有唯一标识符。表格的其余部分包含交易价值、税收、产品、数量等。

标签: sql-server


【解决方案1】:

如果您的表名是 T,您可以使用如下查询 see live demo

select 
ClientCode, 
AvgDays =ISNULL(AVG(d),0)
from
(
    select 
        *, 
        d=DATEDIFF(
                d,
                dateofT,
                LEAD(DateofT) over( 
                        partition by ClientCode 
                        order by DateofT asc )) 
    from t
)t
group by ClientCode

【讨论】:

    【解决方案2】:

    如果您无法使用窗口功能,这里有一个替代方法

    --CREATE SAMPLE DATA
    CREATE TABLE #TMP(ClientID INT, EventDate DATE)
    GO
    
    INSERT INTO #TMP VALUES
    (1,DATEADD(DD,RAND()*365,'20180101'))
    ,(2,DATEADD(DD,RAND()*365,'20180101'))
    ,(3,DATEADD(DD,RAND()*365,'20180101'))
    ,(4,DATEADD(DD,RAND()*365,'20180101'))
    ,(5,DATEADD(DD,RAND()*365,'20180101'))
    GO 50
    
    
    --PRE SQL 2012 Compatible
    SELECT A.ClientID
            ,AVG(DATEDIFF(DD,C.EventDate,A.Eventdate)) AS ClientAvg
    
     FROM #TMP A
        CROSS APPLY (SELECT ClientID, MAX(EventDate) EventDate FROM #TMP B
                        WHERE A.ClientID = B.ClientID AND A.EventDate > B.EventDate
                        GROUP BY ClientID) C
    GROUP BY A.ClientID
    ORDER BY A.ClientID
    

    【讨论】:

    • 如果只有 1 笔交易,这会给 $0$ 吗?
    【解决方案3】:

    您可以使用LAG() 函数按客户将日期与之前的日期进行比较,然后按客户分组并计算平均值。

    IF OBJECT_ID('tempdb..#Transactions') IS NOT NULL
        DROP TABLE #Transactions
    
    CREATE TABLE #Transactions (
        ClientCode VARCHAR(100),
        Date DATE)
    
    INSERT INTO #Transactions (
        ClientCode,
        Date)
    VALUES
        ('DL2', '2016-04-18'),
        ('DL2', '2016-04-19'),
        ('DL2', '2016-04-26'),
    
        ('E19', '2016-01-01'),
        ('E19', '2016-01-11'),
        ('E19', '2016-01-12')
    
    
    ;WITH DayDifferences AS
    (
        SELECT
            T.ClientCode,
            T.Date,
            DayDifference = DATEDIFF(
                DAY,
                LAG(T.Date) OVER (PARTITION BY T.ClientCode ORDER BY T.Date ASC),
                T.Date)
        FROM
            #Transactions AS T
    )
    SELECT
        D.ClientCode,
        AverageDayDifference = AVG(ISNULL(CONVERT(FLOAT, D.DayDifference), 0))
    FROM
        DayDifferences AS D
    GROUP BY
        D.ClientCode
    

    【讨论】:

    • 所以这将创建一个 DayDifference 查询,然后从该表中获取平均值,对吧?在你和 dhruvjoshi 的答案中,我必须为一个非常大的桌子运行这个答案更快
    • @PiyushDivyanakar 两个查询是相似的,应该产生相似的性能。您可能希望在运行之前在 ClientCode、Date 上创建一个索引。
    【解决方案4】:

    使用组内差异之和只是该组的max - min的观察,您可以通过选择使用简单组:

    select IIF(COUNT(*) > 1, 
    (CAST(DATEDIFF(day, MIN(DateofT), MAX(DateofT)) AS FLOAT)) / (COUNT(*) - 1), 0.0) 
    AS AVGDays, ClientCode 
    FROM t GROUP BY ClientCode
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-21
      相关资源
      最近更新 更多