SQL Server Query - groupwise multiplication

后端 未结 3 2029
广开言路
广开言路 2020-11-30 08:31

If we have a table like this:

Grp       Value

Grp1          2
Grp1          5
Grp1          3
Grp2          3
Grp2         -5
Grp2         -2
Grp3                   


        
相关标签:
3条回答
  • 2020-11-30 08:34

    This comes from CodePlex "Aggregate Product function extends SQL". I modified the statement to return the desired results except for the NULL group, it returns "1".

        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/

    0 讨论(0)
  • 2020-11-30 08:36

    Multiplying row values is the same as adding logarithms of row values

    The trick is dealing with zeros and nulls.

    Ok, checked now

    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
    
    0 讨论(0)
  • 2020-11-30 08:45

    At does annoy me that there is no Multiply / Product aggregate function in SQL server. Unfortunately I didn't find the answer @gbn gave above until I'd already solved the problem a different way. I'm posting this alternative solution just in case it helps anyone, or if it turns out to be more efficient.

    My solution basically involves using a recursive common table expression to multiply all the values together.

    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
    

    Starting table (+ the partitioned row number) selects to:

    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
    

    List of ID / Multipliers all multiplied together selects to:

    ID  multiplier  Iteration
    1   1.80000 2
    2   1.70000 1
    3   1.00000 1
    4   0.40000 4
    
    0 讨论(0)
提交回复
热议问题