Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Operatore di aggregazione di moltiplicazione in SQL

Per MUL intendi la moltiplicazione progressiva dei valori?

Anche con 100 righe di piccole dimensioni (diciamo 10 secondi), il tuo MUL (colonna) andrà in overflow qualsiasi tipo di dati! Con una probabilità così elevata di uso improprio/abuso e un ambito di utilizzo molto limitato, non è necessario che sia uno standard SQL. Come altri hanno dimostrato, ci sono modi matematici per risolverlo, così come ci sono molti modi per eseguire calcoli complicati in SQL usando solo metodi standard (e di uso comune).

Dati di esempio:

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 )

Per completezza, le implementazioni principali di 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)))
  • Prestare attenzione quando si utilizza EXP/LOG in SQL Server, controllare il tipo restituito http://msdn.microsoft.com/en-us/library/ms187592.aspx
  • Il modulo POWER consente numeri più grandi (usando basi maggiori del numero di Eulero) e nei casi in cui il risultato diventa troppo grande per tornare indietro usando POWER, puoi restituire solo il valore logaritmico e calcolare il numero effettivo al di fuori del Interrogazione SQL

* LOG(0) e LOG(-ve) non sono definiti. Di seguito viene mostrato solo come gestirlo in SQL Server. È possibile trovare equivalenti per le altre versioni SQL, utilizzando lo stesso concetto

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

Ingredienti:

  • prendendo abs() di dati, se il min è 0, moltiplicando per qualsiasi altra cosa è inutile, il risultato è 0
  • Quando i dati sono 0, NULLIF lo converte in null. Abs(), log() restituiscono entrambi null, facendo in modo che venga precluso da sum()
  • Se i dati non sono 0, abs ci consente di moltiplicare un numero negativo utilizzando il metodo LOG - terremo traccia della negatività altrove
  • Elaborazione del segno finale
    • segno(dati) restituisce 1 for >0 , 0 for 0 e -1 for <0 .
    • Aggiungiamo un altro 0.5 e prendiamo di nuovo il segno(), quindi ora abbiamo classificato 0 e 1 entrambi come 1 e solo -1 come -1.
    • usa nuovamente NULLIF per rimuovere da COUNT() gli 1, poiché dobbiamo solo contare i negativi.
    • % 2 contro il conteggio() dei numeri negativi restituisce uno
    • --> 1 se c'è un numero dispari di numeri negativi
    • --> 0 se c'è un numero pari di numeri negativi
    • altri trucchi matematici:prendiamo 1 o 0 da 0,5, in modo che quanto sopra diventi
    • --> (0.5-1=-0.5 =>arrotonda a -1 ) se c'è un numero dispari di numeri negativi
    • --> (0.5-0= 0.5 =>arrotonda a 1 ) se c'è un numero pari di numeri negativi
    • moltiplichiamo questo 1/-1 finale contro il valore SUM-PRODUCT per il risultato reale