web-dev-qa-db-fra.com

Calcul du pourcentage d'une ligne sur la somme totale

Toutes mes excuses pour le mauvais titre, je ne savais pas ce qui serait un bon titre pour ça.

Il s'agit actuellement (vue simplifiée des) données avec lesquelles je travaille

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

Je dois calculer le pourcentage de la commission totale dont chaque agent est responsable.

Ainsi, pour l'agent Smith, le pourcentage serait calculé comme (Agent Smith's commission / Sum(commission)*100

Donc, mes données attendues seraient

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

J'ai une fonction de restitution de la commission pour chaque agent. J'ai une autre fonction renvoyant le pourcentage comme (Commission/Sum(Commission))*100. Le problème est que Sum(commission) est calculé pour chaque ligne, et étant donné que cette requête serait exécutée sur un entrepôt de données, l'ensemble de données serait plutôt volumineux (actuellement, c'est juste un peu moins de 2000 enregistrements) et assez honnêtement, une mauvaise approche (OMI).

Existe-t-il un moyen de ne pas calculer la Sum(Commission) pour chaque ligne récupérée?

Je pensais à quelque chose sur les lignes d'une requête en 2 parties, la première partie récupérerait la sum(commission) dans une variable/type de package et la deuxième partie ferait référence à cette valeur pré-calculée, mais je ne suis pas sûr comment je peux y arriver.

Je suis limité à l'utilisation de SQL et j'exécute sur Oracle 10g R2.

13
Sathyajith Bhat

Vous recherchez le analytical functionratio_to_report

select 
  agent,
  round(ratio_to_report(commission) over ()*100) "% Comm."
from  
  commissions;
23
René Nyffenegger

Pour renvoyer tous les agents avec leurs commissions et pourcentages de commission, utilisez une fonction analytique sans clause analytique afin que la partition soit sur toute la table:

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

Comme je l'ai appris de René Nyffenegger (+1), la fonction ratio_to_report resserre cette syntaxe.

L'utilisation d'un package pour stocker le SUM de la Commission impliquerait PL/SQL, que vous avez spécifiquement exclu en indiquant que vous souhaitez une solution SQL, mais puisque vous utilisez déjà des fonctions, je suppose que votre intention n'était pas d'exclure PL/SQL. Si tel est le cas, la solution de package peut vous aider, mais cela dépend du fonctionnement de votre application.

Lorsque votre session est créée et appelle la fonction dans le package pour obtenir la commission, il y a un appel implicite au constructeur des packages qui pourrait obtenir la somme et la stocker. Ensuite, vous pouvez référencer la somme stockée dans votre fonction get commission et elle ne devra effectuer la somme qu'une seule fois. Bien sûr, dès que vous appelez la fonction à partir d'une session différente, la somme sera à nouveau calculée. En outre, appeler la fonction pour chaque agent serait considérablement moins efficace que d'appeler une instruction SQL pour tous les agents si votre application pouvait être conçue de cette manière.

Vous pouvez envisager de transformer votre fonction en une procédure qui renvoie un curseur pour la requête ci-dessus ou peut-être avoir une fonction qui renvoie les résultats de la requête sous la forme d'un ensemble de résultats en pipeline.

Exemples de données:

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);
9
Leigh Riffel

Vous pouvez essayer la requête suivante, la somme (commission) ne sera calculée qu'une seule fois:

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;
5
Robert Durgin
  select 
  Agent, Commission,
  (
      ROUND(
       (Commission *100) / 
          (
            (SELECT SUM(Commission)
             FROM commissions AS A)
          )
       ) 
  ) AS Porcentaje
  from  
  commissions
0
JoeDeg