Wie multipliziere ich Zeilen für eine Spalte, die negative und Nullwerte enthält?

10

Ich versuche, das Produkt aller Zeilen für eine bestimmte Spalte in einer nach Abfrage gruppierten zu erhalten. Die meisten Beispiele, die ich gefunden habe, weisen mich auf das Kombinieren hin exp, sumundlog

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

Das Problem, das ich habe, ist, dass die Spalte einige Nullen für Werte enthält und daher dieser Fehler angezeigt wird, wenn Nullen an die logFunktion übergeben werden:

Eine ungültige Gleitkommaoperation ist aufgetreten.

Ich dachte, ich könnte dies mit einem caseAusdruck umgehen, aber das funktioniert einfach nicht so, wie ich es mir vorstellen würde, da es alle Fälle zu bewerten scheint ...

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

Angesichts der folgenden Ergebnismenge:

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

Ich würde erwarten, die folgenden Zeilen zu erhalten:

Name  Product
_____________
a     2
b     0

Also zusammenfassend ... Wie multiplizieren Sie Zeilen in einer Spalte, die negative oder nullwertige Zahlen enthalten können?

Bluetoft
quelle

Antworten:

13

Die Magie von NULLIF scheint den Trick für den Testfall in Ihrer Frage zu tun. Da Sie ein anderes Beispiel als in Ihrer SQL-Geige verwendet haben, weiß ich nicht, ob Sie das auch dort wollen.

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;

Kehrt zurück:

Name    Product
a       2
b       0

Wenn Sie eine allgemeinere Lösung benötigen, die negative Zahlen und andere Randfälle behandelt, lesen Sie beispielsweise Das Produktaggregat in T-SQL im Vergleich zur CLR von Scott Burkow. Eine T-SQL-Konstruktion aus diesem Artikel lautet:

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)

In CASEder Dokumentation zu CASE (Transact-SQL) (Hervorhebung hinzugefügt) wurde erläutert , warum Ihr ursprünglicher Ausdruck nicht wie erwartet funktioniert hat :

Sie sollten sich nur auf die Reihenfolge der Auswertung der WHEN-Bedingungen für skalare Ausdrücke (einschließlich nicht korrelierter Unterabfragen, die Skalare zurückgeben) verlassen, nicht auf aggregierte Ausdrücke .

Erik Darling
quelle