Вот и конец недели, а значит сейчас самое время для небольшого пятничного поста!
Вставал ли перед вами один из этих вопросов
- Как найти произведение значений в столбце?
- Агрегирующая функция произведение?
- Произведение без использование 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 утверждения
- В T-SQL есть очень быстро работающая агрегирующая функция SUM.
- Логарифм произведения равен сумме логарифмов. То есть верны следующие равенства: X*Y = e^ln(X*Y)=e^(ln(X)+ln(Y))
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]Теперь мы получим точно целочисленный ответ.
кстати, круто, может и пригодиться когда-нибудь) а есть что-нибудь по поводу скорости работы такого подхода?
ОтветитьУдалитьПонятно, что такой способ выиграет у T-SQL цикла или курсора.
УдалитьА вот реализация на CLR может побороться за первенство. В будущем обязательно приведу тест для сравнения.