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


315

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

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

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

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

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

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

1
당신 의이 쿼리가 제대로 작동 했습니까 ?? SELECT distributor_id, COUNT(*) AS TOTAL, COUNT(*) WHERE level = 'exec', COUNT(*) WHERE level = 'personal'
Pratik

답변:


689

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

55
환상적입니다. 좋은 대답입니다. 여기에서 우연히 만난 사람들에게만 참고하십시오. Count는 모든 행을 계산하며, case 문과 함께 사용하면 합계는 count와 동일한 작업을 수행합니다.
John Ballinger

1
훌륭한 솔루션! 하위 쿼리를 사용하면 해당 인스턴스에서 상당히 혼란 스러울 수 있으므로 한 쿼리에서 많은 테이블을 함께 결합하는 경우이 방법이 훌륭하게 작동한다는 점에 주목할 가치가 있습니다.
대런 크랩

7
이 매우 우아한 솔루션에 감사드립니다. Btw, 이것은 TSQL에서도 작동합니다.
Annie Lagang

6
이것이 최선의 답변이 아닌 이유 : 항상 전체 테이블 스캔. 카운트 서브 쿼리의 조인 또는 선택에서 중첩 카운트를 고려하십시오. 그러나 인덱스가 없으면 여러 테이블 스캔에 대해 하나의 테이블 스캔 만 보장 한 것이 가장 좋습니다. @KevinBalmforth
YoYo의

1
@JohnBallinger, 'Count는 모든 행을 계산합니다- 현명 COUNT하게 계산 distributor_id합니다. 테이블의 모든 행이 아닙니다.
Istiaque Ahmed

87

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

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의 성능 분석을 참조하십시오. 사람들이 자신의 옵션을 이해할 수 있도록 이것을 남겨두고 있습니다.


2
이를 통해 여러 카운트를 수행하는 방법을 해결하고 각 카운트가 열인 단일 SELECT 문으로 출력 할 수있었습니다. 훌륭하게 작동합니다!
Mark

2
나는 당신이 여기에 제공 한 것을 내 프로젝트에서 사용할 수있었습니다. 이제 모든 것이 여러 쿼리 대신 단일 쿼리에 있습니다. 여러 쿼리에서 5-8 초에 비해 페이지가 1 초 이내에로드됩니다. 그것을 사랑하십시오. 고마워, Notme
Wayne Barron

1
각 하위 쿼리가 실제로 인덱스에 도달하면 제대로 작동 할 수 있습니다. 그렇지 않은 경우 sum(case...)솔루션을 고려해야합니다.
YoYo

1
구별을위한 대안으로, 수정 group by을 한 count(*)것처럼 @Mihai가 보여주는 것처럼 전체 중첩 쿼리를 간단한 것으로 대체 할 수 있습니다 -더 MySQL 전용 구문 단순화로.
YoYo

43
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합니다.


어떤 distributor_id쿼리가 표시됩니까? 총 1 행을 표시합니다.
Istiaque Ahmed

OP에는 내 답변에서 생략 된 열 옆에 그룹이 있습니다.
Majid Laissi

당신은 내 생명을 구했고 다른 모든 aswer는 MySQL에서 여러 행을 반환합니다. 대단히 감사합니다
Abner

1
@Abner는 이것이 8 년 후에도 여전히 도움이된다는 것을 기쁘게 생각합니다 :)
Majid Laissi

@MajidLaissi 예, 쿼리 시간을 1 분에서 1 초 미만으로 변경했습니다. :)
Abner

25

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

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

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는 여전히 훨씬 비쌉니다.


23

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

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

1
?뿐만 아니라이 쿼리에서 정말 필요 ""그룹 distributor_id에 의해 "그것은 그없이 작동 할 수 있었다
user1451111

2
@ user1451111 원래 질문은 답변 자체가 질문 자체에 따라 달라짐
Al-Mothafar

11

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

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;

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


발견 UNION의 여러 인스턴스가 포함 된 보고서 생성 할 때 매우 도움이 될 COUNT(*)기능을.
James O

결과가 표시 #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') FROM distributors UNION SELECT COUNT() AS EXEC_COUNT FROM distributors WHERE ' at line 1됩니다.
Istiaque Ahmed

UNION이 적용되는 모든 쿼리에서 반환 된 열 수는 같아야합니다. @IstiaqueAhmed 아마도 이것이 오류의 원인입니다.
user1451111

미래 에이 답변을 우연히 발견 한 사람을위한 메모. 여기에 설명 된 '처리 후'기술은 '레벨'열의 일부 값이 NULL 인 경우 문제를 일으킬 수 있습니다. 이 경우 모든 하위 개수의 합계가 총 행 개수와 같지 않습니다.
user1451111

6

나는 각 테이블에 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   |
-------------------

1
a query that I created makes ...-그 쿼리는 어디에 있습니까?
Istiaque Ahmed

2
모든 테이블에 caluse를 추가하는 방법

3

다음을 사용하여 뉘앙스가 추가 된 Bluefeet의 승인 된 응답을 기반으로합니다 OVER().

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

OVER()()에 아무것도 사용 하지 않으면 전체 데이터 세트의 총 개수가 제공됩니다.


1

나는 이것이 당신에게도 효과가 있다고 생각합니다. select count(*) as anc,(select count(*) from Patient where sex='F')as patientF,(select count(*) from Patient where sex='M') as patientM from anc

또한 이와 같은 관련 테이블을 선택하고 계산할 수 있습니다. select count(*) as anc,(select count(*) from Patient where Patient.Id=anc.PatientId)as patientF,(select count(*) from Patient where sex='M') as patientM from anc

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.