총합에 대한 행의 백분율 계산


13

나쁜 제목에 대한 사과, 나는 이것에 대한 좋은 제목이 무엇인지 확신하지 못했습니다.

이것은 현재 작업중 인 데이터입니다 (간단한보기).

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

각 요원이 담당하는 총 수수료의 백분율을 계산해야합니다.

따라서 Smith 요원의 경우 백분율은 다음과 같이 계산됩니다. (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)가져 오는 모든 행에 대해 계산하지 않는 방법이 있습니까?

2 부분 쿼리의 줄에 무언가를 생각하고 있었는데, 첫 번째 부분은 sum(commission)패키지 변수 / 유형으로 가져오고 두 번째 부분은이 사전 계산 된 값을 참조하지만 어떻게 이것을 달성 할 수 있는지 잘 모르겠습니다.

SQL을 사용하는 것으로 제한되어 있으며 Oracle 10g R2에서 실행 중입니다.


분명히 DBA 질문은 아닐 것입니다 (아마도 세일즈맨이 아닌 테이블 스페이스 인 경우)? 아마 스택 오버플로에 있어야합니다.
Gaius

답변:


23

당신은 ratio_to_report를 찾고 있습니다analytical function

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

굉장, 이것에 대해 몰랐어요, 감사합니다!
Sathyajith Bhat

9

커미션 및 커미션 백분율이있는 모든 에이전트를 리턴하려면 파티션이 전체 테이블 위에 있도록 분석 절이없는 분석 함수 를 사용 하십시오.

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

René Nyffenegger (+1)에서 배운대로 ratio_to_report 함수는이 구문을 강화합니다.

커미션 SUM을 저장하기 위해 패키지를 사용하는 경우 PL / SQL이 필요합니다. 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

다음 쿼리를 시도하면 sum (commission)이 한 번만 계산됩니다.

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 ~ 수동 방법에는 두 번의 패스가 필요하므로 어떻게 한 번에 패스 할 수 있습니까? 컴퓨터가 어떻게 % ofTotal을 마법의 원 패스 작업으로 만들 수 있는지 알 수 없습니다 ...
jcolebrand

@jcolebrand 데이터는 데이터베이스 블록에서 한 번만 읽습니다. 아마도 메모리 결과에서 여러 번의 패스를 수행하지만 데이터베이스 블록을 두 번 읽는 것보다 일반적으로 빠릅니다. 이 옵션들 사이에 메모리와 CPU에 상충 관계가 있으므로 선택이 항상 명확한 것은 아니지만이 경우에는 그렇게 생각합니다.
레이 리펠

1
@Leigh ~~ 그래, 추가 고려 사항은 블랙 박스 지터 최적화를 통해 내가 할 있는 모든 것을 믿게 만들 것입니다. 어쨌든, 당신의 대답에 멋진 해결책입니다. 감사합니다 : D
jcolebrand

0
  select 
  Agent, Commission,
  (
      ROUND(
       (Commission *100) / 
          (
            (SELECT SUM(Commission)
             FROM commissions AS A)
          )
       ) 
  ) AS Porcentaje
  from  
  commissions
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.