[mysql] 하나의 SQL 쿼리로 여러 카운트를 얻는 방법은 무엇입니까?

이 쿼리를 작성하는 방법이 궁금합니다.

나는이 실제 구문이 가짜라는 것을 알고 있지만, 내가 원하는 것을 이해하는 데 도움이 될 것입니다. 훨씬 큰 쿼리의 일부이기 때문에이 형식으로 필요합니다.

SELECT distributor_id, 
COUNT(*) AS TOTAL, 
COUNT(*) WHERE level = 'exec', 
COUNT(*) WHERE level = 'personal'

이 모든 것이 하나의 쿼리로 반환되어야합니다.

또한 한 행에 있어야하므로 다음이 작동하지 않습니다.

'SELECT distributor_id, COUNT(*)
GROUP BY distributor_id'



답변

CASE집계 함수와 함께 명령문을 사용할 수 있습니다 . 이것은 기본적으로 PIVOT일부 RDBMS 의 함수 와 동일합니다 .

SELECT distributor_id,
    count(*) AS total,
    sum(case when level = 'exec' then 1 else 0 end) AS ExecCount,
    sum(case when level = 'personal' then 1 else 0 end) AS PersonalCount
FROM yourtable
GROUP BY distributor_id


답변

확실하게 작동하는 한 가지 방법

SELECT a.distributor_id,
    (SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
    (SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
    (SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM (SELECT DISTINCT distributor_id FROM myTable) a ;

편집 :
이 방법을 사용하지 않고 @ Taryn ♦의 답변을 선택 해야하는 이유는 @KevinBalmforth의 성능 분석을 참조하십시오. 사람들이 자신의 옵션을 이해할 수 있도록 이것을 남겨두고 있습니다.


답변

SELECT
    distributor_id,
    COUNT(*) AS TOTAL,
    COUNT(IF(level='exec',1,null)),
    COUNT(IF(level='personal',1,null))
FROM sometable;

COUNT값만 계산 non null하고 조건이 충족되는 경우에만 DECODEnull이 아닌 값을 반환 1합니다.


답변

다른 게시 된 답변을 기반으로합니다.

이 두 가지 모두 올바른 값을 생성합니다.

select distributor_id,
    count(*) total,
    sum(case when level = 'exec' then 1 else 0 end) ExecCount,
    sum(case when level = 'personal' then 1 else 0 end) PersonalCount
from yourtable
group by distributor_id

SELECT a.distributor_id,
          (SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
          (SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
          (SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
       FROM myTable a ; 

그러나 성능이 상당히 다르기 때문에 데이터 양이 증가함에 따라 더 관련성이 높습니다.

테이블에 인덱스가 정의되어 있지 않다고 가정하면 SUM을 사용하는 쿼리는 단일 테이블 스캔을 수행하고 COUNT가 포함 된 쿼리는 여러 테이블 스캔을 수행한다는 것을 알았습니다.

예를 들어 다음 스크립트를 실행하십시오.

IF OBJECT_ID (N't1', N'U') IS NOT NULL
drop table t1

create table t1 (f1 int)


    insert into t1 values (1)
    insert into t1 values (1)
    insert into t1 values (2)
    insert into t1 values (2)
    insert into t1 values (2)
    insert into t1 values (3)
    insert into t1 values (3)
    insert into t1 values (3)
    insert into t1 values (3)
    insert into t1 values (4)
    insert into t1 values (4)
    insert into t1 values (4)
    insert into t1 values (4)
    insert into t1 values (4)


SELECT SUM(CASE WHEN f1 = 1 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 2 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 3 THEN 1 else 0 end),
SUM(CASE WHEN f1 = 4 THEN 1 else 0 end)
from t1

SELECT
(select COUNT(*) from t1 where f1 = 1),
(select COUNT(*) from t1 where f1 = 2),
(select COUNT(*) from t1 where f1 = 3),
(select COUNT(*) from t1 where f1 = 4)

2 개의 SELECT 문을 강조 표시하고 Estimated Execution Plan 표시 아이콘을 클릭하십시오. 첫 번째 명령문은 하나의 테이블 스캔을 수행하고 두 번째 명령문은 4를 수행함을 알 수 있습니다. 분명히 하나의 테이블 스캔이 4보다 낫습니다.

클러스터형 인덱스를 추가하는 것도 흥미 롭습니다. 예 :

Create clustered index t1f1 on t1(f1);
Update Statistics t1;

위의 첫 번째 SELECT는 단일 클러스터형 인덱스 스캔을 수행합니다. 두 번째 SELECT는 4 개의 클러스터형 인덱스 검색을 수행하지만 단일 클러스터형 인덱스 스캔보다 여전히 비쌉니다. 나는 800 만 행이있는 테이블에서 같은 것을 시도했지만 두 번째 SELECT는 여전히 훨씬 비쌉니다.


답변

MySQL의 경우 다음과 같이 단축 할 수 있습니다.

SELECT distributor_id,
    COUNT(*) total,
    SUM(level = 'exec') ExecCount,
    SUM(level = 'personal') PersonalCount
FROM yourtable
GROUP BY distributor_id


답변

하나의 쿼리로 모든 것을 가져야하는 경우 통합을 수행 할 수 있습니다.

SELECT distributor_id, COUNT() FROM ... UNION
SELECT COUNT() AS EXEC_COUNT FROM ... WHERE level = 'exec' UNION
SELECT COUNT(*) AS PERSONAL_COUNT FROM ... WHERE level = 'personal';

또는 처리 후 할 수있는 경우 :

SELECT distributor_id, COUNT(*) FROM ... GROUP BY level;

각 레벨의 수를 구하고 총계를 얻으려면 모두 합산해야합니다.


답변

나는 각 테이블에 A 열에서 식별 할 수있는 문자열 이름과 열 수를 제공하는 이와 같은 작업을 수행합니다. 그런 다음 모두 모아서 쌓입니다. 그 결과는 다른 의견과 비교하여 얼마나 효율적인지 확실하지 않지만 필요한 것을 얻었습니다.

select 'table1', count (*) from table1
union select 'table2', count (*) from table2
union select 'table3', count (*) from table3
union select 'table4', count (*) from table4
union select 'table5', count (*) from table5
union select 'table6', count (*) from table6
union select 'table7', count (*) from table7;

결과:

-------------------
| String  | Count |
-------------------
| table1  | 123   |
| table2  | 234   |
| table3  | 345   |
| table4  | 456   |
| table5  | 567   |
-------------------