Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Opérateur d'agrégation de multiplication en SQL

Par MUL, entendez-vous la multiplication progressive des valeurs ?

Même avec 100 lignes de petite taille (disons 10s), votre MUL (colonne) va déborder de n'importe quel type de données ! Avec une telle probabilité d'utilisation erronée/abusive et une portée d'utilisation très limitée, il n'est pas nécessaire qu'il s'agisse d'une norme SQL. Comme d'autres l'ont montré, il existe des moyens mathématiques de le résoudre, tout comme il existe de nombreuses façons d'effectuer des calculs délicats en SQL en utilisant simplement des méthodes standard (et d'usage courant).

Exemple de données :

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 )

Pour être complet, les principales implémentations 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)))
  • Attention lorsque vous utilisez EXP/LOG dans SQL Server, surveillez le type de retour http://msdn.microsoft.com/en-us/library/ms187592.aspx
  • La forme POWER permet des nombres plus grands (en utilisant des bases plus grandes que le nombre d'Euler), et dans les cas où le résultat devient trop grand pour le retourner en utilisant POWER, vous pouvez renvoyer uniquement la valeur logarithmique et calculer le nombre réel en dehors du nombre Requête SQL

* LOG(0) et LOG(-ve) ne sont pas définis. Ce qui suit montre uniquement comment gérer cela dans SQL Server. Des équivalents peuvent être trouvés pour les autres saveurs SQL, en utilisant le même concept

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

Ingrédients :

  • en prenant l'abs() des données, si le min est 0, en multipliant par tout ce qui est futile, le résultat est 0
  • Lorsque data est 0, NULLIF le convertit en null. Les abs(), log() renvoient tous les deux null, ce qui les exclut de sum()
  • Si les données ne sont pas 0, abs nous permet de multiplier un nombre négatif à l'aide de la méthode LOG - nous garderons une trace de la négativité ailleurs
  • Travailler sur le signe final
    • sign(data) renvoie 1 for >0 , 0 for 0 et -1 for <0 .
    • Nous ajoutons un autre 0,5 et reprenons le signe(), nous avons donc maintenant classé 0 et 1 comme 1, et seulement -1 comme -1.
    • utilisez à nouveau NULLIF pour supprimer de COUNT() les 1, car nous n'avons qu'à compter les négatifs.
    • % 2 contre le count() des nombres négatifs renvoie soit
    • --> 1 s'il y a un nombre impair de nombres négatifs
    • --> 0 s'il y a un nombre pair de nombres négatifs
    • Plus d'astuces mathématiques :nous retirons 1 ou 0 de 0,5, de sorte que ce qui précède devient
    • --> (0.5-1=-0.5 =>arrondir à -1 ) s'il y a un nombre impair de nombres négatifs
    • --> (0.5-0= 0.5 =>arrondir à 1 ) s'il y a un nombre pair de nombres négatifs
    • nous multiplions ce 1/-1 final par la valeur SUM-PRODUCT pour le résultat réel