문제

다음과 같은 데이터가있는 Oracle 테이블이 있습니다.

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

그건, ID 기본 키는 기본 키이고 각 "배치"마다 여러 행이 있으며 각 행에는 상태 코드가 있습니다. 상태 열. 다른 많은 열이 있지만 이것들은 중요한 열입니다.

요약 할 쿼리를 작성해야합니다. 상태 코드 각각 일괄; 상태 열, 0, 1 및 2에 갈 수있는 세 가지 가능한 값이 있으며 다음과 같은 모습을 보이는 출력을 원합니다.

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

그 숫자는 계산 될 것입니다. 배치 1에는 있습니다

  • 2 개의 레코드 위치 상태 0으로 설정됩니다
  • 1 레코드 위치 상태 1로 설정되어 있습니다
  • 어디에 기록이 없습니다 상태 0으로 설정됩니다.

Batch 2의 경우 있습니다

  • 1 레코드 위치 상태 0으로 설정되어 있습니다
  • 어디에 기록이 없습니다 상태 1 또는 2로 설정됩니다.

각 상태 코드에 대한 쿼리를 다시 작성하지 않고도 한 쿼리 에서이 작업을 수행 할 수있는 방법이 있습니까? 즉, 이와 같은 쿼리를 쉽게 쓸 수 있고 세 번 실행할 수 있습니다.

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

나는 그것을 실행할 수 있고, 상태 = 1에서 다시 실행할 수 있고, 상태 = 2로 다시 실행할 수는 있지만, 한 쿼리에서 그것을하기를 바라고 있습니다.

그것이 차이를 만든다면 상태 열이 있습니다 또 다른 동일한 방식으로 요약하고 싶은 열-Select 문을 작성한 후 Select 문을 실행하고 모든 결과를 Amalgamate 할 필요가없는 다른 이유입니다.

도움이 되었습니까?

해결책

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-Specific이지만 덜 장점) :

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;

다른 팁

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
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

OP는 한 접근 방식 (합)의 성능 이점이 있는지 묻습니다 (카운트). 26K 행으로 테이블에서 단순한 테스트를 실행하면 카운트 접근 방식이 훨씬 빠릅니다. 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

캐싱의 효과를 제거하기 위해 테스트를 몇 번 반복했습니다. 또한 Select 문을 교환했습니다. 결과는 전반적으로 비슷했습니다.

편집 : 이것은 내가 대답했던 것과 동일한 테스트 하네스입니다. 비슷한 질문 와 함께.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top