合計に対する行の割合の計算


13

悪いタイトルをおologiesび申し上げますが、これに適したタイトルになるかどうかはわかりませんでした。

これは現在(の簡略化されたビュー)私が作業しているデータです

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)フェッチされるすべての行に対して計算しないようにする方法はありますか?

私は2つの部分のクエリの行で何かを考えていました。最初の部分はsum(commission)パッケージ変数/タイプにフェッチし、2番目の部分はこの事前に計算された値を参照しますが、これをどのように達成できるかわかりません。

SQLの使用に制限されており、Oracle 10g R2で実行しています。


明らかにDBAの質問ではありません(おそらく、セールスマンではなくテーブルスペースだったのでしょうか?)-おそらくStack Overflowにあるはずです。
ガイウス

回答:



9

すべてのエージェントにコミッションとコミッション率を返すには、分析句のない分析関数を使用して、パーティションがテーブル全体に渡るようにします。

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

RenéNyffenegger(+1)から学んだように、ration_to_report関数はこの構文を強化します。

パッケージを使用してCommission SUMを保存するには、SQLソリューションが必要であることを示すことで特に除外したPL / SQLが必要ですが、すでに関数を使用しているため、PL / SQLを除外するつもりはなかったと思います。この場合、パッケージソリューションが役立つ場合がありますが、アプリケーションの動作に依存します。

セッションが最初に作成され、パッケージ内の関数を呼び出してコミッションを取得すると、合計を取得して格納できるパッケージコンストラクターへの暗黙的な呼び出しがあります。次に、コミッション取得関数で保存された合計を参照できます。合計を一度実行するだけで済みます。もちろん、別のセッションから関数を呼び出すとすぐに、合計が再び計算されます。また、アプリケーションをそのように設計できる場合、すべてのエージェントに対して関数を呼び出すことは、すべてのエージェントに対して1つの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;

これは機能し、正しいデータを返しますが、2回ではなく1回の全テーブルスキャンを実行する分析関数よりも効率的ではありません(インデックスがないと仮定)。
リーリッフェル

1
@Leigh〜手動の方法では2つのパスが必要なため、1つのパスでどのように実行できますか?私は...コンピュータは%ofTotal魔法ワンパス操作を行うことができるか見ることができない
jcolebrand

@jcolebrandデータはデータベースブロックから1回だけ読み取られます。メモリ内の結果の複数のパスを実行している可能性がありますが、これは通常、データベースブロックを2回読み取るよりも高速です。これらのオプションの間にはメモリと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.