пятница, 13 июля 2012 г.

Произведение

Вот и конец недели, а значит сейчас самое время для небольшого пятничного поста! Вставал ли перед вами один из этих вопросов
  • Как найти произведение значений в столбце?
  • Агрегирующая функция произведение?
  • Произведение без использование CLR?
Перефразируем вопрос с помощью кода. Как имея такие данные
CREATE TABLE [Data](
 [objectId] [int] NOT NULL
   ,[value] [int] NOT NULL
);
GO

insert into [Data] ([objectId],[value])
          select 1, 2
union all select 1, 2
union all select 1, 2
union all select 1, 2
union all select 1, 2

union all select 2, 7
union all select 2, 2
union all select 2, 3
union all select 2, 2

union all select 3, 1
union all select 3, 3
union all select 3, 5
 
Получить следующий результат.
objectId    multiplication
----------- --------------
1           32            --2*2*2*2*2
2           84            --7*2*3*2
3           15            --1*3*5
Если проблема вам знакома, то прошу под кат

Решение

Сейчас я приведу небольшой хак как можно это сделать. Идея хака опирается на 2 утверждения
  1. В T-SQL есть очень быстро работающая агрегирующая функция SUM.
  2. Логарифм произведения равен сумме логарифмов. То есть верны следующие равенства: X*Y = e^ln(X*Y)=e^(ln(X)+ln(Y))
Запишем эту идею с помощью T-SQL
  
select  
    [objectId]
   ,EXP(SUM(LOG([value]))) [multiplication]
from [Data]
group by [objectId]
 

О чем всегда нужно помнить?

Функция EXP возвращает значение типа float, это может привести к ситуации, когда мы, перемножая целые числа, получим дробный ответ. Например 2 умножим на 2, а в результате возвращается не 4, а 3,999999998. Чтобы этого избежать можно подстраховаться.
  
select  
 [objectId]
   ,CAST(ROUND(EXP(SUM(LOG([value]))),0) as int) [multiplication]
from [Data]
group by [objectId]
 
Теперь мы получим точно целочисленный ответ.

2 комментария:

  1. кстати, круто, может и пригодиться когда-нибудь) а есть что-нибудь по поводу скорости работы такого подхода?

    ОтветитьУдалить
    Ответы
    1. Понятно, что такой способ выиграет у T-SQL цикла или курсора.
      А вот реализация на CLR может побороться за первенство. В будущем обязательно приведу тест для сравнения.

      Удалить