Come moltiplicare le righe per una colonna che contiene valori negativi e zero?


10

Sto cercando di ottenere il prodotto di tutte le righe per una colonna specifica in un raggruppato per query. La maggior parte degli esempi che ho trovato punto di me verso la combinazione exp, sumelog

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

Il problema che sto riscontrando è che la colonna contiene alcuni zeri per i valori e quindi visualizzo questo errore quando gli zeri vengono passati alla logfunzione:

Si è verificata un'operazione in virgola mobile non valida.

Pensavo di poter aggirare questo problema usando caseun'espressione, ma non funziona come penserei che dovrebbe, visto che sembra valutare tutti i casi ...

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

Dato il seguente set di risultati:

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

Mi aspetterei di ottenere le seguenti righe:

Name  Product
_____________
a     2
b     0

Quindi in sintesi ... Come si moltiplicano le righe in una colonna che possono contenere numeri negativi o con valore zero?

Risposte:


13

La magia di NULLIF sembra fare il trucco per il test case nella tua domanda. Dato che hai usato un esempio diverso rispetto al tuo SQL Fiddle, non so se è quello che vuoi anche lì.

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;

Ritorna:

Name    Product
a       2
b       0

Se hai bisogno di una soluzione più generale che gestisca numeri negativi e altri casi limite, vedi ad esempio The Product Aggregate in T-SQL vs. CLR di Scott Burkow. Una costruzione T-SQL di quell'articolo è:

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)

Per quanto riguarda il motivo per cui l' CASEespressione originale non ha funzionato come previsto, dalla documentazione per CASE (Transact-SQL) (enfasi aggiunta):

Dovresti dipendere solo dall'ordine di valutazione delle condizioni QUANDO per le espressioni scalari (comprese le sottoquery non correlate che restituiscono gli scalari), non per le espressioni aggregate .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.