如何通过一个SQL查询获得多个计数?

时间:2022-07-24 11:10:49

I am wondering how to write this query.

我想知道如何写这个查询。

I know this actual syntax is bogus, but it will help you understand what I am wanting. I need it in this format, because it is part of a much bigger query.

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

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

I need this all returned in one query.

我需要在一个查询中返回所有这些。

Also, it need to be in one row, so the following won't work:

另外,它需要排在一行中,所以以下内容不能用:

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

9 个解决方案

#1


437  

You can use a CASE statement with an aggregate function. This is basically the same thing as a PIVOT function in some RDBMS:

您可以使用一个带有聚合函数的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

#2


58  

One way which works for sure

一种肯定有效的方法

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 ;

EDIT:
See @KevinBalmforth's break down of performance for why you likely don't want to use this method and instead should opt for @bluefeet's answer. I'm leaving this so people can understand their options.

编辑:查看@KevinBalmforth的性能分解,了解为什么您可能不想使用这个方法,而应该选择@bluefeet的答案。我把这个留给人们去理解他们的选择。

#3


31  

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

COUNT only counts non null values and the DECODE will return non null value 1 only if your condition is satisfied.

计数只计数非空值和解码将返回非空值1,只有当你的条件是满足。

#4


16  

For mysql this can be shorten to

对于mysql,这可以缩短为。

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

#5


13  

Building on other posted answers.

在其他张贴的答案上建立。

Both of these will produce the right values:

两者都将产生正确的值:

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 ; 

However, the performance is quite different, which will obviously be more relevant as the quantity of data grows.

但是,性能是完全不同的,随着数据量的增加,这显然更加相关。

I found that, assuming no indexes were defined on the table, the query using the SUMs would do a single table scan, while the query with the COUNTs would do multiple table scans.

我发现,假设表上没有定义索引,使用和的查询将执行单个表扫描,而具有计数的查询将执行多个表扫描。

As an example, run the following script:

例如,运行以下脚本:

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)

Highlight the 2 SELECT statements and click on the Display Estimated Execution Plan icon. You will see that the first statement will do one table scan and the second will do 4. Obviously one table scan is better than 4.

突出显示2个SELECT语句并单击显示的估计执行计划图标。您将看到,第一个语句将执行一个表扫描,第二个语句将执行4。显然,一个表扫描比4要好。

Adding a clustered index is also interesting. E.g.

添加集群索引也很有趣。如。

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

The first SELECT above will do a single Clustered Index Scan. The second SELECT will do 4 Clustered Index Seeks, but they are still more expensive than a single Clustered Index Scan. I tried the same thing on a table with 8 million rows and the second SELECT was still a lot more expensive.

上面的第一个SELECT将执行单个聚集索引扫描。第二个选择将执行4个聚集索引查找,但是它们仍然比单个聚集索引扫描更昂贵。我在一张有800万排的桌子上尝试了同样的东西,第二选择仍然要贵得多。

#6


7  

Well, if you must have it all in one query, you could do a union:

如果你必须在一个查询中包含所有内容,你可以做一个联合:

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

Or, if you can do after processing:

或者,如果你可以做后处理:

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

You will get the count for each level and need to sum them all up to get the total.

您将得到每一层的计数,并需要将它们加起来以得到总数。

#7


3  

I do something like this where I just give each table a string name to identify it in column A, and a count for column. Then I union them all so they stack. The result is pretty in my opinion - not sure how efficient it is compared to other options but it got me what I needed.

我做了这样的事情,给每个表一个字符串名,在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;

Result:

结果:

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

#8


0  

Based on Bluefeet's accepted response with an added nuance using OVER ()

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

Using OVER() with nothing in the () will give you the total count for the whole dataset.

在()中不包含任何内容的情况下使用OVER()将给出整个数据集的总数。

#9


0  

I think this can also works for you select count(*) as anc,(select count(*) from Patient where sex='F')as patientF,(select count(*) from Patient where sex='M') as patientM from anc

我认为这也适用于你选择count(*)作为非国大,(select count(*) from Patient where sex='F')作为patientF,(select count(*) from Patient where sex='M')作为anc的patientM。

and also you can select and count related tables like this 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

您还可以选择和计算相关的表,如选择count(*)作为anc,(选择count(*)来自病人。id =anc.PatientId)作为patientF,(选择count(*)来自病人,其中性别='M')作为patientM来自anc

#1


437  

You can use a CASE statement with an aggregate function. This is basically the same thing as a PIVOT function in some RDBMS:

您可以使用一个带有聚合函数的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

#2


58  

One way which works for sure

一种肯定有效的方法

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 ;

EDIT:
See @KevinBalmforth's break down of performance for why you likely don't want to use this method and instead should opt for @bluefeet's answer. I'm leaving this so people can understand their options.

编辑:查看@KevinBalmforth的性能分解,了解为什么您可能不想使用这个方法,而应该选择@bluefeet的答案。我把这个留给人们去理解他们的选择。

#3


31  

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

COUNT only counts non null values and the DECODE will return non null value 1 only if your condition is satisfied.

计数只计数非空值和解码将返回非空值1,只有当你的条件是满足。

#4


16  

For mysql this can be shorten to

对于mysql,这可以缩短为。

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

#5


13  

Building on other posted answers.

在其他张贴的答案上建立。

Both of these will produce the right values:

两者都将产生正确的值:

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 ; 

However, the performance is quite different, which will obviously be more relevant as the quantity of data grows.

但是,性能是完全不同的,随着数据量的增加,这显然更加相关。

I found that, assuming no indexes were defined on the table, the query using the SUMs would do a single table scan, while the query with the COUNTs would do multiple table scans.

我发现,假设表上没有定义索引,使用和的查询将执行单个表扫描,而具有计数的查询将执行多个表扫描。

As an example, run the following script:

例如,运行以下脚本:

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)

Highlight the 2 SELECT statements and click on the Display Estimated Execution Plan icon. You will see that the first statement will do one table scan and the second will do 4. Obviously one table scan is better than 4.

突出显示2个SELECT语句并单击显示的估计执行计划图标。您将看到,第一个语句将执行一个表扫描,第二个语句将执行4。显然,一个表扫描比4要好。

Adding a clustered index is also interesting. E.g.

添加集群索引也很有趣。如。

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

The first SELECT above will do a single Clustered Index Scan. The second SELECT will do 4 Clustered Index Seeks, but they are still more expensive than a single Clustered Index Scan. I tried the same thing on a table with 8 million rows and the second SELECT was still a lot more expensive.

上面的第一个SELECT将执行单个聚集索引扫描。第二个选择将执行4个聚集索引查找,但是它们仍然比单个聚集索引扫描更昂贵。我在一张有800万排的桌子上尝试了同样的东西,第二选择仍然要贵得多。

#6


7  

Well, if you must have it all in one query, you could do a union:

如果你必须在一个查询中包含所有内容,你可以做一个联合:

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

Or, if you can do after processing:

或者,如果你可以做后处理:

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

You will get the count for each level and need to sum them all up to get the total.

您将得到每一层的计数,并需要将它们加起来以得到总数。

#7


3  

I do something like this where I just give each table a string name to identify it in column A, and a count for column. Then I union them all so they stack. The result is pretty in my opinion - not sure how efficient it is compared to other options but it got me what I needed.

我做了这样的事情,给每个表一个字符串名,在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;

Result:

结果:

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

#8


0  

Based on Bluefeet's accepted response with an added nuance using OVER ()

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

Using OVER() with nothing in the () will give you the total count for the whole dataset.

在()中不包含任何内容的情况下使用OVER()将给出整个数据集的总数。

#9


0  

I think this can also works for you select count(*) as anc,(select count(*) from Patient where sex='F')as patientF,(select count(*) from Patient where sex='M') as patientM from anc

我认为这也适用于你选择count(*)作为非国大,(select count(*) from Patient where sex='F')作为patientF,(select count(*) from Patient where sex='M')作为anc的patientM。

and also you can select and count related tables like this 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

您还可以选择和计算相关的表,如选择count(*)作为anc,(选择count(*)来自病人。id =anc.PatientId)作为patientF,(选择count(*)来自病人,其中性别='M')作为patientM来自anc