2009-02-25 11 views
0

Ich habe vor kurzem eine Abfrage in SQL erstellt, die ich verwenden kann, um unser Zahlungsprotokoll anzuzeigen und eine durchschnittliche Anzahl von Zahlungen pro Stunde über einen bestimmten Zeitraum zu ermitteln. Ich bin mir sicher, dass es Reporting-Anwendungen von Drittanbietern gibt, die viel besser für die Art von Berechnungen geeignet sind, die ich versuche. Aber nur zum Spaß bin ich neugierig darauf, welche anderen Methoden Sie verwenden könnten T-SQL), um die gesuchten Daten zu erhalten. Ich weiß, es ist eine dumme Frage, also werde ich nicht beleidigt sein, wenn du mich abstimmst. Aber für jeden anderen da draußen, der wie ich gelangweilt ist, kannst du deine anderen Lösungen posten.Optimieren einer Abfrage zum Erstellen von Durchschnitten

Die Tabelle wird mit einer Spalte [CreateDate] eingerichtet, bei der es sich um den DATETIME-Wert handelt, wenn die Zahlung auf das Konto gebucht wird. Ich benutze dies, um zu bestimmen, welche Stunde sie in die Zahlung.

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

Antwort

1

IIUC Sie aus der Haupttabelle sind Filterung unter Verwendung eines mit der temporären Tabelle verbinden.

Warum nicht den Join löschen und nur eine Where-Klausel verwenden? Wenn Sie alle Stunden zwingen möchten, sich zu zeigen, machen Sie die Verbindung nach den Rest der Arbeit oder verwenden Sie eine Union irgendeiner Art.

+0

Guter Punkt. Ich könnte UNION die Tabelle und dann eine Summe ([Count]) und GROUP BY in allen Zeilen später, um die Daten zusammen zu tun. Das wäre wahrscheinlich weniger Arbeit für die Proc. – regex

1

Ich denke, das ist eine ziemlich nette Methode. Es vermeidet die Verwendung einer Stunden-Tabelle (oder einer temporären Tabelle, wie Sie sie verwenden). Der Nachteil ist, dass es nur Werte für Stunden anzeigt, an denen eine Zahlung vorgenommen wurde. Lassen Sie das Front-End alle 0s setzen. :)

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 
+0

Die Verwendung von String-Manipulation als Proxy für DateTime-Manipulation ist extrem ineffizient ... – MatBailie

+0

Sie könnten sicherlich andere Methoden verwenden, um die Minuten/Sekunden/Millisekunden abzuschneiden. Das war einfach am einfachsten zu programmieren und zu verstehen. Die Grundidee ist jedoch immer noch die gleiche. –

+0

Sehr klug in der Tat. Ihr COUNT (*) + 1 funktioniert jedoch nicht, wenn nur eine Zahlung für diese Stunde erfolgt. Dann erscheint es als 2 :(Ich habe versucht einen Weg zu finden, damit es funktioniert, aber die Abfrage ist einfach zu unmöglich. Danke, dass du mir für den Rest des Tages etwas zu tun hast :) – regex