Розрахунок відсотка рядка від загальної суми


13

Вибачте за поганий титул, я не був впевнений, що буде хорошим титулом для цього.

Наразі це дані (спрощений перегляд) даних, з якими я працюю

Agent    |  Commission     
---------|------------
Smith    |    100
Neo      |    200
Morpheus |    300

Мені потрібно підрахувати відсоток від загальної комісії, за що відповідає кожен агент.

Отже, для агента Сміта відсоток буде обчислюватися як (Agent Smith's commission / Sum(commission)*100

Отже, мої очікувані дані будуть

Agent    |  Commission   |  % Commission    
---------|---------------|---------------
Smith    |    100        |     17
Neo      |    200        |     33
Morpheus |    300        |     50

У мене є функція повернення комісії за кожного агента. У мене є ще одна функція, що повертає відсоток як (Commission/Sum(Commission))*100. Проблема полягає в тому, що Sum(commission)обчислюється для кожного ряду, а враховуючи, що цей запит буде виконуватися в сховищі даних, набір даних буде досить великим (на даний момент це трохи менше 2000 записів) і, чесно кажучи, поганим підходом (IMO ).

Чи існує спосіб Sum(Commission)не обчислити кожен отриманий рядок?

Я щось думав у рядках запиту з двох частин, перша частина отримала sum(commission)змінну / тип пакету, а друга частина посилалася б на це попередньо обчислене значення, але я не впевнений, як мені це досягти.

Я обмежений використанням SQL, і я працюю на Oracle 10g R2.


Не очевидно, що питання про DBA (можливо, якщо це просто табличні простори, а не продавці?) - мабуть, має бути на стеці переповнення.
Гай

Відповіді:



9

Щоб повернути всі агенти з їх комісіями та відсотками комісій, використовуйте аналітичну функцію без аналітичного застереження, щоб розділ був над усією таблицею:

SELECT Agent, commission, 100* commission / (SUM(commission) OVER ()) "% Commission" 
FROM commissions;

Як я дізнався від Рене Ніффенеггера (+1), функція ratio_to_report підтягує цей синтаксис.

Використання пакета для зберігання комісії SUM передбачає PL / SQL, який ви спеціально виключили, вказавши, що хочете рішення SQL, але оскільки ви вже використовуєте функції, я припускаю, що ваш намір не полягав у тому, щоб виключити PL / SQL. Якщо це так, можливо, пакетне рішення допоможе, але це залежить від того, як працює ваша програма.

Коли ваш сеанс вперше створений і викликає функцію в пакеті, щоб отримати комісію, відбувається неявний виклик конструктору пакунків, який міг би отримати суму і зберегти її. Тоді ви можете посилатися на збережену суму у функції отримання комісії, і суму доведеться робити лише один раз. Звичайно, як тільки ви викликаєте функцію з іншого сеансу, сума буде обчислена знову. Крім того, виклик функції для кожного агента було б значно менш ефективним, ніж виклик одного оператора SQL для всіх агентів, якщо ваша програма може бути розроблена таким чином.

Ви можете розглянути можливість перетворення вашої функції в процедуру, яка повертає курсор для вищезазначеного запиту або, можливо, має функцію, яка повертає результати запиту як набір конвеєрних результатів.

Приклад даних:

create table commissions (Agent Varchar2(100), Commission Number(3));
insert into commissions values ('Smith',100);
insert into commissions values ('Neo',200);
insert into commissions values ('Morpheus',300);

5

Ви можете спробувати наступний запит, сума (комісія) буде обчислена лише один раз:

WITH TOTAL_COMMISSION AS 
(SELECT SUM(COMMISSION) AS TOTAL FROM AGENTS)
SELECT A.AGENT_NAME, A.COMMISSION, ((A.COMMISSION/T.TOTAL)*100) AS "% COMMISSION"
FROM AGENTS A, TOTAL_COMMISSION T;

Це працює і повертає правильні дані, але є менш ефективними, ніж аналітична функція, яка виконує одне сканування повної таблиці, а не два (за умови, що немає індексів).
Лей Ріффел

1
@Leigh ~ Як це можна зробити за один прохід, оскільки ручний спосіб вимагає двох пропусків? Я не бачу, як комп’ютери могли б зробити% з загальної магічної операції з одним проходом ...
jcolebrand

@jcolebrand Дані читаються з блоків бази даних лише один раз. Можливо, це робить кілька пропусків його в результатах пам'яті, але це, як правило, швидше, ніж читання блоків бази даних двічі. Між цими опціями є компроміси в пам'яті та процесорі, тому вибір не завжди може бути чітким, але в цьому випадку я думаю, що це так.
Лей Ріффел

1
@Leigh ~~ Так, подальший розгляд призведе до того, що я вважаю, що це все, що можна зробити, просто чорна скринька стрибнула оптимізаціями. У будь-якому випадку вишукане рішення у вашій відповіді. Спасибі: D
jcolebrand

0
  select 
  Agent, Commission,
  (
      ROUND(
       (Commission *100) / 
          (
            (SELECT SUM(Commission)
             FROM commissions AS A)
          )
       ) 
  ) AS Porcentaje
  from  
  commissions
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.