2

次のようなデータを含む Oracle テーブルがあります。

ID   BATCH   STATUS
1    1       0
2    1       0
3    1       1
4    2       0

つまり、IDが主キーで、「バッチ」ごとに複数の行があり、各行のSTATUS列にステータス コードがあります。他にもたくさんのコラムがありますが、これらは重要なものです。

バッチのステータス コードを要約するクエリを作成する必要があります。STATUS 列には、0、1、および 2 の 3 つの可能な値があり、次のような出力が必要です。

BATCH  STATUS0  STATUS1  STATUS2
1      2        1        0
2      1        0        0

これらの数値はカウントになります。バッチ 1 の場合、

  • STATUSが 0 に設定されている2 つのレコード
  • STATUSが 1 に設定されている 1 つのレコード、および
  • STATUSが 0 に設定されて いるレコードはありません。

バッチ 2 には、

  • STATUSが 0 に設定されている1 つのレコード、および
  • STATUSが 1 または 2 に設定されているレコードはありません。

ステータス コードごとにクエリを書き直すことなく、1 つのクエリでこれを行う方法はありますか? つまり、次のようなクエリを簡単に作成して、3 回実行できます。

SELECT batch, COUNT(status)
FROM table
WHERE status = 0
GROUP BY batch

それを実行してから、ステータス = 1 の場所でもう一度実行し、ステータス = 2 の場所でもう一度実行することもできますが、1 つのクエリで実行したいと考えています。

違いがある場合は、STATUS列以外に、同じ方法で要約したい別の列があります。これは、SELECT ステートメントの後に SELECT ステートメントを実行し、すべての結果を結合する必要がないもう 1 つの理由です。

4

4 に答える 4

6
select batch 
,      count(case when status=1 then 1 end) status1
,      count(case when status=2 then 1 end) status2
,      count(case when status=3 then 1 end) status3
from   table
group by batch;

これは「ピボット」クエリと呼ばれることが多く、ブログでこれらのクエリを動的に生成する方法についての記事を書いています。

DECODE を使用したバージョン (Oracle 固有ですが、冗長ではありません):

select batch 
,      count(decode(status,1,1)) status1
,      count(decode(status,2,1)) status2
,      count(decode(status,3,1)) status3
from   table
group by batch;
于 2009-06-22T19:45:04.927 に答える
1

OPは、あるアプローチ(SUM)が他のアプローチ(COUNT)よりもパフォーマンス上の利点があるかどうかを尋ねます。単純なテストを 26,000 行のテーブルで実行すると、COUNT アプローチの方が大幅に高速であることがわかります。YMMV。

DECLARE
  CURSOR B IS
     select batch_id
       FROM batch
      WHERE ROWNUM < 2000;

  v_t1  NUMBER;
  v_t2  NUMBER;
  v_c1  NUMBER;
  v_c2  NUMBER;
  v_opn INTEGER;
  v_cls INTEGER;
  v_btc VARCHAR2(100);
BEGIN
-- Loop using SUM
  v_t1 := dbms_utility.get_time;
  v_c1 := dbms_utility.get_cpu_time;
  FOR R IN B LOOP
     FOR R2 IN (SELECT batch_type_code
                     , SUM(decode(batch_status_code, 'CLOSED', 1, 0)) closed
                     , SUM(decode(batch_status_code, 'OPEN', 1, 0)) OPEN
                     , SUM(decode(batch_status_code, 'REWORK', 1, 0)) rework
                  FROM batch
                 GROUP BY batch_type_code) LOOP 
        v_opn := R2.open;
        v_cls := R2.closed;
     END LOOP;
  END LOOP;
  v_t2 := dbms_utility.get_time;
  v_c2 := dbms_utility.get_cpu_time;
  dbms_output.put_line('For loop using SUM:');
  dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
  dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);

-- Loop using COUNT
  v_t1 := dbms_utility.get_time;
  v_c1 := dbms_utility.get_cpu_time;
  FOR R IN B LOOP
     FOR R2 IN (SELECT batch_type_code
                     , COUNT(CASE WHEN batch_status_code = 'CLOSED' THEN 1 END) closed
                     , COUNT(CASE WHEN batch_status_code = 'OPEN' THEN 1 END) OPEN
                     , COUNT(CASE WHEN batch_status_code = 'REWORK' THEN 1 END) rework
                  FROM batch
                 GROUP BY batch_type_code) LOOP 
        v_opn := R2.open;
        v_cls := R2.closed;
     END LOOP;
  END LOOP;
  v_t2 := dbms_utility.get_time;
  v_c2 := dbms_utility.get_cpu_time;
  dbms_output.put_line('For loop using COUNT:');
  dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
  dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
END;
/

これにより、次の出力が得られました。

For loop using SUM:
CPU seconds used: 40
Elapsed time: 40.09
For loop using COUNT:
CPU seconds used: 33.26
Elapsed time: 33.34

キャッシュの影響を排除するために、テストを数回繰り返しました。また、選択ステートメントを交換しました。結果は全体的に同様でした。

編集: これは、同様の質問に答えるために使用したのと同じテスト ハーネスです。

于 2009-06-22T23:18:49.253 に答える
1
select batch,
sum(select case when status = 0 then 1 else 0 end) status0,
sum(select case when status = 1 then 1 else 0 end) status1,
sum(select case when status = 2 then 1 else 0 end) status2
from table
group by batch
于 2009-06-22T19:43:29.003 に答える
1
select batch,
sum((decode(status,0,1,0)) status0,
sum((decode(status,1,1,0)) status1,
sum((decode(status,2,1,0)) status2,
from table
group by batch
于 2009-06-22T19:48:11.787 に答える