2017-07-29 5 views
2

Wir versuchen, einen gleitenden Durchschnitt zu berechnen und haben versucht, zahlreiche SO-Antworten zu konvertieren, um das Problem zu lösen. Bis zu diesem Punkt sind wir immer noch nicht erfolgreich.Berechnen eines rekursiven gleitenden Durchschnitts in SQL Server

Was wir versucht haben:

Hier sind einige der SO Antworten, die wir in Betracht gezogen haben.

Unsere neueste Versuch war eine der Lösungen (# 4) hier zu ändern. https://www.red-gate.com/simple-talk/sql/t-sql-programming/calculating-values-within-a-rolling-window-in-transact-sql/

Beispiel:

Hier ein Beispiel in SQL Fiddle ist: http://sqlfiddle.com/#!6/4570a/17

In der Geige, versuchen wir immer noch um die Summe zu erhalten Recht auf Arbeit, aber letztlich das bekommen wir versuchen, durchschnittlich.

Das Endziel

die Fiddle Beispiel verwenden, müssen wir den Unterschied zwischen Wert1 und ComparisonValue1 finden und sie als Diff1 präsentieren. Wenn für eine Zeile kein Value1 verfügbar ist, müssen wir sie schätzen, indem wir den Durchschnitt der letzten beiden Diff1-Werte nehmen und ihn dann dem ComparisonValue1 für diese Zeile hinzufügen.

Mit der richtigen Abfrage, wäre das Ergebnis wie folgt aussehen:

GroupID Number ComparisonValue1 Diff1 Value1 
5  10  54.78    2.41 57.19 
5  11  55.91    2.62 58.53 
5  12  55.93    2.78 58.71 
5  13  56.54    2.7 59.24 
5  14  56.14    2.74 58.88 
5  15  55.57    2.72 58.29 
5  16  55.26    2.73 57.99 

Frage: ist es möglich, diesen Mittelwert zu berechnen, wenn es möglicherweise in den Durchschnitt der folgenden Zeilen Faktor könnte?

aktualisieren:

  • Added einen Blick auf das Fiddle-Schema die endgültige Abfrage zu vereinfachen.
  • Die Abfrage wurde aktualisiert, um den neuen fortlaufenden Durchschnitt für Diff1 (Spalte Diff1Last2Avg) einzuschließen. Dieser gleitende Durchschnittswert funktioniert gut, bis wir in der Spalte Wert1 auf Nullen stoßen. Hier müssen wir die Schätzung einfügen.
  • Die query aktualisiert, um die Schätzung einzuschließen, die verwendet werden sollte, wenn es keinen Wert1 (Spalte Value1Estimate) gibt. Dies funktioniert hervorragend und wäre perfekt, wenn wir die Schätzung anstelle von NULL in der Spalte Wert1 verwenden könnten. Da die Diff1-Spalte die Differenz zwischen Value1 (oder dessen Schätzung) und ComparisonValue1 widerspiegelt, würde die Schätzung alle NULL-Werte in Diff1 enthalten. Dies würde wiederum ermöglichen, die Schätzungen zukünftiger Reihen zu berechnen. Es wird an dieser Stelle verwirrend, aber hackt immer noch davon ab. Irgendwelche Ideen?
+0

Wenn möglich, reduzieren Sie die Anzahl der Datensätze und fügen Sie das erwartete Ergebnis im fraglichen Tabellenformat hinzu. Gute Frage –

+0

Welche Version von SQL? – Xedni

+0

@Xedni SQL Server 2008 –

Antwort

0

Kredit für die Idee geht auf diese Antwort: https://stackoverflow.com/a/35152131/6305294 von @ JesúsLópez

ich Kommentare im Code enthalten sind, es zu erklären.

UPDATE

  • ich auf Kommentare Abfrage korrigiert haben.
  • Ich habe Zahlen in Minuend und Subtrahend ausgetauscht, um die Differenz als positive Zahl zu erhalten.
  • Entfernte Diff2Ago-Spalte.

Die Ergebnisse der Abfrage stimmen nun exakt mit Ihrer Beispielausgabe überein.

;WITH cte AS 
(
    -- This is similar to your ItemWithComparison view 
    SELECT i.Number, i.Value1, i2.Value1 AS ComparisonValue1, 
     -- Calculated Differences; NULL will be returned when i.Value1 is NULL 
     CONVERT(DECIMAL(10, 3), i.Value1 - i2.Value1) AS Diff 
    FROM Item AS i 
      LEFT JOIN [Group] AS G ON g.ID = i.GroupID 
      LEFT JOIN Item AS i2 ON i2.GroupID = g.ComparisonGroupID AND i2.Number = i.Number 
    WHERE NOT i2.Id IS NULL 
), 
cte2 AS(
    /* 
    Start with the first number 

    Note if you do not have at least 2 consecutive numbers (in cte) with non-NULL Diff value and therefore Diff1Ago or Diff2Ago are NULL then everything else will not work; 
    You may need to add additional logic to handle these cases */ 
    SELECT TOP 1 -- start with the 1st number (see ORDER BY) 
      a.Number, a.Value1, a.ComparisonValue1, a.Diff, b.Diff AS Diff1Ago 
    FROM cte AS a 
      -- "1 number ago" 
      LEFT JOIN cte AS b ON a.Number - 1 = b.Number 
    WHERE NOT a.Value1 IS NULL 
    ORDER BY a.Number 
    UNION ALL 
    SELECT b.Number, b.Value1, b.ComparisonValue1, 
      (CASE 
       WHEN NOT b.Value1 IS NULL THEN b.Diff 
       ELSE CONVERT(DECIMAL(10, 3), (a.Diff + a.Diff1Ago)/2.0) 
      END) AS Diff, 
     a.Diff AS Diff1Ago 
    FROM cte2 AS a 
     INNER JOIN cte AS b ON a.Number + 1 = b.Number 
) 
SELECT *, (CASE WHEN Value1 IS NULL THEN ComparisonValue1 + Diff ELSE Value1 END) AS NewValue1 
FROM cte2 OPTION(MAXRECURSION 0); 

Einschränkungen: diese Lösung funktioniert nur dann gut, wenn Sie kleine Anzahl vorhergehender Werte müssen berücksichtigen.

+0

Wow, ganz in der Nähe. Ein paar kleinere Probleme wurden behoben, aber jetzt läuft es in [fiddle] (http://sqlfiddle.com/#!6/4570a/41). Die Ergebnisse stimmen zwar nicht mit den Stichprobenergebnissen in der Frage überein. Die Schätzung für den ersten Value1-Nullwert sollte 59,24 sein. Habe ich etwas kaputt gemacht, als ich die Anfrage verschoben habe? Ich werde es überprüfen. –

+0

Außerdem wurde die ABS-Funktion entfernt, da die negativen Werte für unsere Anwendung wichtig sind. –

+0

Ich glaube, die CASE ELSE-Zeile in der rekursiven cte2-Abfrage muss "ELSE CONVERT (DECIMAL (10, 3), (a.Diff + a.Diff1Ago)/2.0)" sein. –

Verwandte Themen