Jak pomnożyć wiersze dla kolumny zawierającej wartości ujemne i zerowe?

10

Usiłuję uzyskać iloczyn wszystkich wierszy dla określonej kolumny w grupie pogrupowanej według zapytania. Większość przykładów mam punkt znalazł mnie w kierunku łączenia exp, sumilog

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

Problem, który mam, polega na tym, że kolumna zawiera niektóre zera wartości, dlatego otrzymuję ten błąd, gdy zera są przekazywane do logfunkcji:

Wystąpiła niepoprawna operacja zmiennoprzecinkowa.

Myślałem, że mogę to obejść za pomocą casewyrażenia, ale to po prostu nie działa tak, jak myślałem, że powinno, ponieważ wydaje się, że ocenia wszystkie przypadki ...

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

Biorąc pod uwagę następujący zestaw wyników:

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

Spodziewałbym się uzyskać następujące wiersze:

Name  Product
_____________
a     2
b     0

Podsumowując ... Jak pomnożyć wiersze w kolumnie, która może zawierać liczby ujemne lub wartości zerowe?

bluetoft
źródło

Odpowiedzi:

13

Wydaje się, że magia NULLIF rozwiązuje problem testowy w twoim pytaniu. Ponieważ użyłeś innego przykładu niż w swoim SQL Fiddle, nie wiem, czy tego też tam chcesz.

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;

Zwroty:

Name    Product
a       2
b       0

Jeśli potrzebujesz bardziej ogólnego rozwiązania, które obsługuje liczby ujemne i inne przypadki brzegowe, zobacz na przykład Agregat produktu w T-SQL kontra CLR autorstwa Scotta Burkowa. Jedna konstrukcja T-SQL z tego artykułu to:

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)

Dlaczego oryginalne CASEwyrażenie nie działało zgodnie z oczekiwaniami, z dokumentacji CASE (Transact-SQL) (wyróżnienie dodane):

Należy polegać tylko na kolejności oceny warunków KIEDY dla wyrażeń skalarnych (w tym nieskorelowanych podzapytań zwracających skalary), a nie dla wyrażeń agregujących .

Erik Darling
źródło