2010-09-06 23 views
8

如果我们有这样的一个表:SQL Server查询 - GroupWise的乘法

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 

我们如何组/乘得到这个?

GrpID  Value 

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

回答

18

乘行值是一样的添加行对数的值

诀窍是处理零和空值。

好了,现在检查

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

为什么CASE WHEN值<1?它不应该是<0? – zvolkov 2011-08-30 14:18:17

+0

@zvolkov:是的,它应该。样本数据没有> 0和<1的值,所以错过了这个条件。谢谢 – gbn 2011-08-30 15:57:57

1

在不惹恼我,有在SQL服务器中没有乘法/产品聚合函数。 不幸的是,我没有找到@gbn给出的答案,直到我已经以不同的方式解决了这个问题。我发布了这个替代解决方案,以防万一它帮助任何人,或者如果它变得更高效。

我的解决方案基本上涉及使用递归公用表表达式将所有值相乘。

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 

启动表(+分割行编号)选择到:

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 

ID的列表/乘法器所有乘在一起选择,以:

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

这来自CodePlex上的“集合产品功能扩展SQL“。我修改了语句以返回除NULL组之外的所需结果,它返回“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/