如何使用一个SQL查询获取多个计数?

时间:2012-10-08 21:00:05

标签: mysql sql join count group-by

我想知道如何编写此查询。

我知道这个实际的语法是假的,但它会帮助你理解我想要的东西。 我需要这种格式,因为它是更大查询的一部分。

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

我需要在一个查询中返回所有内容。

此外,它需要在一行中,因此以下操作无效:

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

9 个答案:

答案 0 :(得分:550)

您可以使用带有聚合函数的CASE语句。这与某些RDBMS中的PIVOT函数基本相同:

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

答案 1 :(得分:73)

一种确实有效的方法

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 ;

修改
 请参阅@ KevinBalmforth的性能分解,了解为什么您可能不想使用此方法,而应选择@ bluefeet的答案。我离开了,所以人们可以理解他们的选择。

答案 2 :(得分:35)

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

COUNT仅计算non null个值,DECODE只有在满足条件时才会返回非空值1

答案 3 :(得分:20)

以其他已发布的答案为基础。

这两个都会产生正确的值:

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语句,然后单击Display Estimated Execution Plan图标。您将看到第一个语句将执行一个表扫描,第二个语句将执行4.显然,一个表扫描优于4个。

添加聚簇索引也很有趣。 E.g。

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

上面的第一个SELECT将执行单个Clustered Index Scan。第二个SELECT将执行4个Clustered Index Seeks,但它们仍然比单个Clustered Index Scan更昂贵。我在一个有800万行的表上尝试了同样的事情,第二个SELECT仍然要贵得多。

答案 4 :(得分:19)

对于mysql,这可以缩短为

select distributor_id,
    count(*) total,
    sum(level = 'exec') ExecCount,
    sum(level = 'personal') PersonalCount
from yourtable
group by distributor_id

答案 5 :(得分:10)

好吧,如果你必须在一个查询中拥有它,你可以做一个联合:

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;

您将获得每个级别的计数,并需要将它们全部加起来以获得总数。

答案 6 :(得分:4)

我做了类似这样的事情,我只给每个表一个字符串名称以在列A中标识它,并为列计数。然后我把他们联合起来,所以他们堆叠。结果在我看来很不错 - 不确定它与其他选项相比有多高效,但它让我得到了我需要的东西。

<input type="text" id="name">

<p id="nah">Please Enter Name!</p>
<p id="yah">Thank you!</p>

<button id="button">Complete Form</button>

<强>结果:

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;

答案 7 :(得分:1)

基于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()将为您提供整个数据集的总计数。

答案 8 :(得分:0)

我认为这也适用于你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