优化查询以构建平均值

时间:2009-02-25 22:36:48

标签: sql sql-server tsql

我最近在SQL中构建了一个查询,我可以用来查看我们的付款日志,并找出一段时间内每小时的平均付款次数。我确信有第三方报告应用程序更适合做我正在尝试的计算类型,但只是为了好玩,我很想知道你们可能使用的其他方法(在T-SQL)获取我正在寻找的数据。我知道这是一个愚蠢的问题,所以如果你投票给我,我不会被冒犯。但是,对于像我这样无聊的其他人,请随意发布您的其他解决方案。

该表设置有[CreateDate]列,该列是付款过帐到帐户时的DATETIME值。我用这个来确定他们付款的时间。

CREATE TABLE #TempTimes
(
    [Time] DATETIME,
)

DECLARE @numDays INT
SET @numDays = 10
DECLARE @time DATETIME
SET @time = DATEADD(dd, DATEDIFF(dd, 0, GETDATE() - @numDays), 0)

WHILE @time < GETDATE()
BEGIN
    INSERT #TempTimes
    VALUES (@time)

    SET @time = DATEADD(hour, 1, @time)
END
GO
/*
I have to join in a table with all of the hours for the time span I'm querying against, 
because otherwise, the AVG function won't calculate in the hours where no payments were made. 
*/

SELECT DATEPART(hour, [Time]) [Hour], AVG(CAST([Count] AS DECIMAL)) [Average]
FROM 
(
    SELECT [Time], CASE WHEN [Count] IS NULL THEN 0 ELSE [Count] END [Count]
    FROM #TempTimes tt
    LEFT JOIN 
    (
        SELECT DATEADD(hour, DATEDIFF(hour, 0, [CreateDate]), 0) [hour], COUNT(*) [Count]
        FROM [dbo].[PaymentLog]
        GROUP BY DATEADD(hour, DATEDIFF(hour, 0, [CreateDate]), 0)
    ) t1 ON t1.[hour] = tt.[time]
) t2
GROUP BY DATEPART(hour, tt.[Time])
GO

DROP TABLE #TempTimes
GO

CJ

2 个答案:

答案 0 :(得分:1)

您正在使用与临时表的连接从主表中过滤的IIUC。

为什么不删除连接并只使用where子句?如果您想强制显示所有时间,请在之后加入,或使用某种联合。

答案 1 :(得分:1)

我认为这是一个相当漂亮的方法。它避免使用Hours表(或像你正在使用的临时表)。缺点是它只显示付款的小时值。让前端全部放入0。 :)

CREATE TABLE dbo.Payments
(
    payment_id  INT IDENTITY    NOT NULL,
    create_date DATETIME        NOT NULL,
    CONSTRAINT PK_Payments PRIMARY KEY CLUSTERED (payment_id)
)
GO

INSERT INTO dbo.Payments (create_date)
SELECT '2009-02-25 12:00:00.000' UNION
SELECT '2009-02-25 12:45:00.000' UNION
SELECT '2009-02-25 12:30:00.000' UNION
SELECT '2009-02-25 13:10:00.000' UNION
SELECT '2009-02-25 13:22:00.000' UNION
SELECT '2009-02-25 14:09:00.000' UNION
SELECT '2009-02-25 14:40:00.000'
GO

SELECT
    CAST(CONVERT(VARCHAR(13), T1.create_date, 121) + ':00:00.000' AS DATETIME),
    COUNT(T3.payment_id) + 1
FROM
    dbo.Payments T1
LEFT OUTER JOIN dbo.Payments T2 ON
    T2.create_date >= CAST(CONVERT(VARCHAR(13), T1.create_date, 121) + ':00:00.000' AS DATETIME) AND
    T2.create_date <  T1.create_date
LEFT OUTER JOIN dbo.Payments T3 ON
    T3.create_date >= T1.create_date AND
    T3.create_date <  DATEADD(hh, 1, CAST(CONVERT(VARCHAR(13), T1.create_date, 121) + ':00:00.000' AS DATETIME)) AND
    T3.payment_id <> T1.payment_id
WHERE
    T2.payment_id IS NULL
GROUP BY
    CAST(CONVERT(VARCHAR(13), T1.create_date, 121) + ':00:00.000' AS DATETIME)
GO