Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Multiplikations-Aggregatoperator in SQL

Mit MUL meinen Sie die progressive Multiplikation von Werten?

Selbst mit 100 Zeilen mit einer kleinen Größe (z. B. 10s) wird Ihre MUL (Spalte) jeden Datentyp überlaufen lassen! Bei einer so hohen Wahrscheinlichkeit von Fehl-/Missbrauch und einem sehr begrenzten Anwendungsbereich muss es kein SQL-Standard sein. Wie andere gezeigt haben, gibt es mathematische Möglichkeiten, es zu berechnen, genauso wie es viele, viele Möglichkeiten gibt, knifflige Berechnungen in SQL durchzuführen, indem man einfach Standardmethoden (und allgemein gebräuchliche) Methoden verwendet.

Beispieldaten:

Column
1
2
4
8

COUNT : 4 items (1 for each non-null)
SUM   : 1 + 2 + 4 + 8 = 15
AVG   : 3.75 (SUM/COUNT)
MUL   : 1 x 2 x 4 x 8 ? ( =64 )

Der Vollständigkeit halber die Core-Implementierungen von Oracle, MSSQL, MySQL *

Oracle : EXP(SUM(LN(column)))   or  POWER(N,SUM(LOG(column, N)))
MSSQL  : EXP(SUM(LOG(column)))  or  POWER(N,SUM(LOG(column)/LOG(N)))
MySQL  : EXP(SUM(LOG(column)))  or  POW(N,SUM(LOG(N,column)))
  • Achten Sie bei der Verwendung von EXP/LOG in SQL Server auf den Rückgabetyp http://msdn.microsoft.com/en-us/library/ms187592.aspx
  • Die POTENZ-Form erlaubt größere Zahlen (unter Verwendung von Basen, die größer als die Euler-Zahl sind), und in Fällen, in denen das Ergebnis zu groß wird, um es mit POWER umzukehren, können Sie nur den logarithmischen Wert zurückgeben und die tatsächliche Zahl außerhalb von berechnen SQL-Abfrage

* LOG(0) und LOG(-ve) sind undefiniert. Im Folgenden wird nur gezeigt, wie dies in SQL Server gehandhabt wird. Äquivalente können für die anderen SQL-Varianten gefunden werden, die dasselbe Konzept verwenden

create table MUL(data int)
insert MUL select 1 yourColumn union all
           select 2 union all
           select 4 union all
           select 8 union all
           select -2 union all
           select 0

select CASE WHEN MIN(abs(data)) = 0 then 0 ELSE
       EXP(SUM(Log(abs(nullif(data,0))))) -- the base mathematics
     * round(0.5-count(nullif(sign(sign(data)+0.5),1))%2,0) -- pairs up negatives
       END
from MUL

Zutaten:

  • Nehmen der abs() von Daten, wenn das Minimum 0 ist, multiplizieren mit was auch immer sonst sinnlos ist, das Ergebnis ist 0
  • Wenn data 0 ist, wandelt NULLIF es in null um. Sowohl abs() als auch log() geben null zurück, was dazu führt, dass es von sum() ausgeschlossen wird
  • Wenn Daten nicht 0 sind, erlaubt uns abs, eine negative Zahl mit der LOG-Methode zu multiplizieren - wir werden die Negativität an anderer Stelle verfolgen
  • Ausarbeitung des Endzeichens
    • sign(data) gibt 1 for >0 zurück , 0 for 0 und -1 for <0 .
    • Wir fügen weitere 0,5 hinzu und nehmen wieder das Zeichen(), sodass wir jetzt 0 und 1 beide als 1 und nur -1 als -1 klassifiziert haben.
    • Verwenden Sie wieder NULLIF, um aus COUNT() die Einsen zu entfernen, da wir nur die negativen Zahlen hochzählen müssen.
    • % 2 gegen die count() von negativen Zahlen gibt entweder
    • --> 1, wenn es eine ungerade Anzahl negativer Zahlen gibt
    • --> 0, wenn es eine gerade Anzahl negativer Zahlen gibt
    • Weitere mathematische Tricks:Wir ziehen 1 oder 0 von 0,5 ab, sodass Obiges wird
    • --> (0.5-1=-0.5 =>runden auf -1 ), wenn es eine ungerade Anzahl negativer Zahlen gibt
    • --> (0.5-0= 0.5 =>runden auf 1 ), wenn es eine gerade Anzahl negativer Zahlen gibt
    • Wir multiplizieren dieses abschließende 1/-1 mit dem SUM-PRODUCT-Wert für das tatsächliche Ergebnis