Como multiplicar linhas para uma coluna que contém valores negativos e zero?

10

Estou tentando obter o produto de todas as linhas para uma coluna específica em um agrupado por consulta. A maioria dos exemplos que eu encontrei ponto mim para combinar exp, sumelog

exp(sum(log([Column A])))

O problema que estou tendo é que a coluna contém alguns zeros para valores e, portanto, estou recebendo esse erro quando zeros são passados ​​para a logfunção:

Ocorreu uma operação inválida de ponto flutuante.

Eu pensei que poderia contornar isso usando uma caseexpressão, mas isso simplesmente não funciona da maneira que eu acho que deveria, pois parece avaliar todos os casos ...

select 
  Name,
  Product = case 
    when min([Value]) = 0 then 0 
    when min([Value]) <> 0 then exp(sum(log(I))) -- trying to get the product of all rows in this column
  end
 from ids
 group by Name

SqlFiddle

Dado o seguinte conjunto de resultados:

Id  Name  Value
_________________________________
1   a     1
2   a     2
3   b     0
4   b     1

Eu esperaria obter as seguintes linhas:

Name  Product
_____________
a     2
b     0

Então, em resumo ... Como você multiplica linhas em uma coluna que pode conter números negativos ou com valor zero?

bluetoft
fonte

Respostas:

13

A mágica do NULLIF parece fazer o truque para o caso de teste em sua pergunta. Como você usou um exemplo diferente do SQL Fiddle, não sei se é isso que você deseja também.

CREATE TABLE dbo.Ids
(
    Id INT NOT NULL IDENTITY(1, 1),
    Value INT,
    Name NVARCHAR(3)
);
INSERT INTO dbo.Ids ( Name, Value )
VALUES ( 'a', 1 );
INSERT INTO dbo.Ids ( Name, Value )
VALUES ( 'a', 2 );
INSERT INTO dbo.Ids ( Name, Value )
VALUES ( 'b', 0 );
INSERT INTO dbo.Ids ( Name, Value )
VALUES ( 'b', 1 );

SELECT   Name,
         CASE WHEN MIN(Value) = 0 THEN 0
              WHEN MIN(Value) > 0 THEN EXP(SUM(LOG(NULLIF(Value, 0)))) -- trying to get the product of all rows in this column
         END AS Product
FROM     Ids
GROUP BY Name;

Devoluções:

Name    Product
a       2
b       0

Se você precisar de uma solução mais geral que lide com números negativos e outros casos extremos , consulte, por exemplo, O produto agregado no T-SQL versus o CLR de Scott Burkow. Uma construção T-SQL desse artigo é:

EXP(SUM(LOG(NULLIF(ABS([Value]), 0))))
*
IIF(SUM(IIF([Value] = 0, 1, NULL)) > 0, 0, 1)
*
IIF(SUM(IIF([Value] < 0, 1, 0)) % 2 = 1, -1, 1)

Por que sua CASEexpressão original não funcionou conforme o esperado, na documentação do CASE (Transact-SQL) (ênfase adicionada):

Você deve depender apenas da ordem de avaliação das condições WHEN para expressões escalares (incluindo subconsultas não correlacionadas que retornam escalares), não para expressões agregadas .

Erik Darling
fonte