Подтвердить что ты не робот

Оператор агрегации Mutiplication в SQL

В SQL есть агрегирующие операторы, такие как AVG, SUM, COUNT. Почему у него нет оператора для умножения? "MUL" или что-то в этом роде.

Мне было интересно, существует ли это для Oracle, MSSQL, MySQL? Если нет, это обходное решение, которое даст такое поведение?

4b9b3361

Ответ 1

По MUL вы имеете в виду прогрессивное умножение значений?

Даже со 100 строками небольшого размера (скажем, 10) ваш MUL (столбец) будет переполнять любой тип данных! С такой высокой вероятностью неправильного использования и ограниченного объема использования, он не должен быть стандартом SQL. Как показали другие, существуют математические способы его разработки, так же как есть много способов сделать сложные вычисления в SQL, используя стандартные (и общеупотребительные) методы.

Пример данных:

Column
1
2
4
8

COUNT : 4 items (1 for each non-null)
SUM   : 1 + 2 + 4 + 8 = 15
AVG   : 3.75 (SUM/COUNT)
MUL   : 1 x 2 x 4 x 8 ? ( =64 )

Для полноты, реализации ядра Oracle, MSSQL, MySQL *

Oracle : EXP(SUM(LN(column)))   or  POWER(N,SUM(LOG(column, N)))
MSSQL  : EXP(SUM(LOG(column)))  or  POWER(N,SUM(LOG(column)/LOG(N)))
MySQL  : EXP(SUM(LOG(column)))  or  POW(N,SUM(LOG(N,column)))
  • Уход при использовании EXP/LOG в SQL Server, посмотрите тип возврата http://msdn.microsoft.com/en-us/library/ms187592.aspx
  • Форма POWER позволяет использовать большие числа (используя базы, большие, чем число Эйлера), а в случаях, когда результат становится слишком большим, чтобы вернуть его с помощью POWER, вы можете вернуть только логарифмическое значение и вычислить фактическое число за пределами Запрос SQL


* LOG (0) и LOG (-ve) - undefined. Ниже показано только, как обрабатывать это в SQL Server. Эквиваленты могут быть найдены для других SQL-вкусов, используя ту же концепцию

create table MUL(data int)
insert MUL select 1 yourColumn union all
           select 2 union all
           select 4 union all
           select 8 union all
           select -2 union all
           select 0

select CASE WHEN MIN(abs(data)) = 0 then 0 ELSE
       EXP(SUM(Log(abs(nullif(data,0))))) -- the base mathematics
     * round(0.5-count(nullif(sign(sign(data)+0.5),1))%2,0) -- pairs up negatives
       END
from MUL

Ингредиенты:

  • принимая abs() данных, если min равно 0, умножая на то, что еще бесполезно, результат равен 0
  • Когда данные равны 0, NULLIF преобразует его в нуль. Абс(), log() возвращают null, заставляя его исключаться из sum()
  • Если данные не равны 0, abs позволяет нам использовать несколько отрицательных чисел с помощью метода LOG - мы будем отслеживать негативность в другом месте
  • Разработка окончательного знака
    • знак (данные) возвращает 1 for >0, 0 for 0 и -1 for <0.
    • Добавим еще 0.5 и снова возьмем знак(), поэтому теперь мы классифицировали 0 и 1 как 1, а только -1 как -1.
    • снова используйте NULLIF для удаления из COUNT() 1, так как нам нужно только подсчитать негативы.
    • % 2 против count() отрицательных чисел возвращает либо
    • → 1, если существует нечетное число отрицательных чисел
    • → 0, если существует четное число отрицательных чисел
    • более математические трюки: мы берем 1 или 0 от 0,5, так что выше это становится
    • → (0.5-1=-0.5= > round to -1), если есть нечетное число отрицательных чисел
    • → (0.5-0= 0.5= > round to 1), если существует четное число отрицательных чисел
    • мы умножим этот окончательный 1/-1 на значение SUM-PRODUCT для реального результата

Ответ 2

Нет, но вы можете использовать математику:)

если yourColumn всегда больше нуля:

select EXP(SUM(LOG(yourColumn))) As ColumnProduct from yourTable

Ответ 3

Я вижу, что ответ Oracle по-прежнему отсутствует, так что вот оно:

SQL> with yourTable as
  2  ( select 1 yourColumn from dual union all
  3    select 2 from dual union all
  4    select 4 from dual union all
  5    select 8 from dual
  6  )
  7  select EXP(SUM(LN(yourColumn))) As ColumnProduct from yourTable
  8  /

COLUMNPRODUCT
-------------
           64

1 row selected.

С уважением,
Роб.

Ответ 4

С помощью PostgreSQL вы можете создавать свои собственные агрегатные функции, см. http://www.postgresql.org/docs/8.2/interactive/sql-createaggregate.html

Чтобы создать агрегатную функцию в MySQL, вам нужно будет создать файл .so(linux) или .dll(windows). Пример показан здесь: http://www.codeproject.com/KB/database/mygroupconcat.aspx

Я не уверен в mssql и оракуле, но я уверен, что у них есть опции для создания настраиваемых агрегатов.

Ответ 5

Вы быстро сломаете любой тип данных, когда числа будут установлены вверх.

Использование LOG/EXP сложно из-за чисел <= 0, которые будут сбой при использовании LOG. Я написал решение в этом вопросе, которое касается этого

Ответ 6

Использование CTE в MS SQL:

CREATE TABLE Foo(Id int, Val int)
INSERT INTO Foo VALUES(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)

;WITH cte AS 
(
    SELECT Id, Val AS Multiply, row_number() over (order by Id) as rn
    FROM Foo
    WHERE Id=1
    UNION ALL
    SELECT ff.Id, cte.multiply*ff.Val as multiply, ff.rn FROM
    (SELECT f.Id, f.Val, (row_number() over (order by f.Id)) as rn
    FROM Foo f) ff
        INNER JOIN cte
        ON ff.rn -1= cte.rn
)
SELECT * FROM cte

Ответ 7

Не уверен в Oracle или sql-сервере, но в MySQL вы можете просто использовать *, как обычно.

mysql> select count(id), count(id)*10 from tablename;
+-----------+--------------+
| count(id) | count(id)*10 |
+-----------+--------------+
|       961 |         9610 |
+-----------+--------------+
1 row in set (0.00 sec)