2010-09-06 7 views
8

Wenn wir eine Tabelle wie folgt aus:SQL Server Query - groupwise Multiplikation

Grp  Value 

Grp1   2 
Grp1   5 
Grp1   3 
Grp2   3 
Grp2   -5 
Grp2   -2 
Grp3   4 
Grp3   0 
Grp3   1 
Grp4   -2 
Grp4   -4 
Grp5   7 
Grp5  NULL 
Grp6  NULL 
Grp6  NULL 
Grp7   -1 
Grp7  10 

Wie können wir Gruppe/multiplizieren diese zu bekommen?

GrpID  Value 

Grp1  30 
Grp2  30 
Grp3  0 
Grp4  8 
Grp5  7 
Grp6  NULL 
Grp7  -10 

Antwort

18

Zeilenwerte Multipliziert ist das gleiche wie die Logarithmen der Zeilen Hinzufügen von Werten

Der Trick mit Nullen und Nullen handelt.

Ok, überprüft jetzt

DECLARE @foo TABLE (GrpID varchar(10), Value float) 

INSERt @foo (GrpID, Value) 
SELECT 'Grp1',   2 
UNION ALL SELECT 'Grp1',   5 
UNION ALL SELECT 'Grp1',   3 
UNION ALL SELECT 'Grp2',   3 
UNION ALL SELECT 'Grp2',   -5 
UNION ALL SELECT 'Grp2',   -2 
UNION ALL SELECT 'Grp3',   4 
UNION ALL SELECT 'Grp3',   0 
UNION ALL SELECT 'Grp3',   1 
UNION ALL SELECT 'Grp4',   -2 
UNION ALL SELECT 'Grp4',   -4 
UNION ALL SELECT 'Grp5',   7 
UNION ALL SELECT 'Grp5',  NULL 
UNION ALL SELECT 'Grp6',  NULL 
UNION ALL SELECT 'Grp6',  NULL 
UNION ALL SELECT 'Grp7',   -1 
UNION ALL SELECT 'Grp7',  10 

SELECT 
    GrpID, 
    CASE 
     WHEN MinVal = 0 THEN 0 
     WHEN Neg % 2 = 1 THEN -1 * EXP(ABSMult) 
     ELSE EXP(ABSMult) 
    END 
FROM 
    (
    SELECT 
     GrpID, 
     --log of +ve row values 
     SUM(LOG(ABS(NULLIF(Value, 0)))) AS ABSMult, 
     --count of -ve values. Even = +ve result. 
     SUM(SIGN(CASE WHEN Value < 0 THEN 1 ELSE 0 END)) AS Neg, 
     --anything * zero = zero 
     MIN(ABS(Value)) AS MinVal 
    FROM 
     @foo 
    GROUP BY 
     GrpID 
    ) foo 
+1

Warum CASE WHEN Wert <1? sollte es nicht <0 sein? – zvolkov

+0

@zvolkov: Ja, sollte es. Die Beispieldaten haben keine Werte> 0 und <1, so dass diese Bedingung nicht erfüllt wurde. Vielen Dank – gbn

1

Bei mir tut ärgern, dass es keine Multiply/Produktaggregatfunktion in SQL Server. Leider habe ich oben die Antwort @gbn nicht gefunden, bis ich das Problem schon anders gelöst hatte. Ich poste diese alternative Lösung für den Fall, dass es irgendjemandem hilft oder wenn es sich als effizienter herausstellt.

Meine Lösung beinhaltet grundsätzlich die Verwendung eines rekursiven allgemeinen Tabellenausdrucks, um alle Werte zu multiplizieren.

DECLARE @t TABLE (PID INT, ID INT, multiplier DECIMAL(14,5)) 

INSERT @t 
     (PID, ID, multiplier) 
VALUES (1, 1, 1.5) 
     , (2, 1, 1.2) 
     , (3, 2, 1.7) 
     , (4, 3, 1) 
     , (5, 4, 0.8) 
     , (6, 4, 0.5) 
     , (7, 4, 2) 
     , (8, 4, 0.5) 

SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY PID) 
FROM @t; 


WITH 
trn AS 
(
SELECT PID, ID, multiplier, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY PID) AS rn 
FROM @t 
), 
tmu AS 
(
    SELECT DISTINCT 
     ID, 
     trn.multiplier AS multiplier, 
     1 AS Iteration 
    FROM trn WHERE rn = 1 
    UNION ALL 
    SELECT 
     trn.ID, CAST(tmu.multiplier * trn.multiplier AS DECIMAL(14,5)) AS multiplier 
     , tmu.Iteration + 1 AS Iteration 
    FROM 
     tmu --AS tmu1 
     JOIN trn ON tmu.ID = trn.ID AND tmu.Iteration + 1 = trn.rn 
), 
mxi AS 
(
    SELECT ID, COUNT(ID) AS Iter 
    FROM trn 
    GROUP BY ID 
) 

SELECT tmu.* 
FROM tmu 
    JOIN mxi ON mxi.ID = tmu.ID AND mxi.Iter = tmu.Iteration 
ORDER BY ID 

Ausgangstabelle (+ die partitionierte Zeilennummer) auswählt:

PID ID Multiplier rn 
1 1 1.50000 1 
2 1 1.20000 2 
3 2 1.70000 1 
4 3 1.00000 1 
5 4 0.80000 1 
6 4 0.50000 2 
7 4 2.00000 3 
8 4 0.50000 4 

Liste der ID/all Multiplizierern zusammen auswählt:

ID multiplier Iteration 
1 1.80000 2 
2 1.70000 1 
3 1.00000 1 
4 0.40000 4 
1

Das kommt von CodePlex „Aggregate Produktfunktion erweitert SQL ". Ich änderte die Anweisung, um die gewünschten Ergebnisse außer der NULL-Gruppe zurückzugeben, es gibt "1" zurück.

SELECT GrpID, Exp(Sum(IIf(Abs(ISNULL(value,1))=0,0,Log(Abs(ISNULL(value,1))))))*IIf(Min(Abs(ISNULL(value,1)))=0,0,1)* 
(1-2*(Sum(IIf(ISNULL(value,1)>=0,0,1)) % 2)) AS value 
    FROM @foo 
    GROUP BY GrpID; 

GrpID  Value 

Grp1  30 
Grp2  30 
Grp3  0 
Grp4  8 
Grp5  7 
Grp6  1 
Grp7  -10 

ref: http://productfunctionsql.codeplex.com/