SQL 服务器 - 计算总值和过滤值

SQL Server - Calculate total and filtered value

我有以下数据集:

Machine Type Value
1        A  11
1        B  32
2        A  23
3        A  1
4        B  23
4        B  31
5        B  56
6        A  12

我想进行以下计算:

SELECT COUNT(WHERE TYPE = A) / COUNT(TOTAL)
FROM....

最好的方法是什么?正在使用 With like:

DECLARE @CNT INT
SET @CNT = (SELECT COUNT(*) FROM dataset)
SELECT COUNT(*)/CNT
FROM dataset
WHERE TYPE = A

但是,如果我有一个大查询,为这个计算重复相同的查询会使 SQL 变慢...任何人都可以提供更好的解决方案吗?

使用 case 表达式进行条件计数。

(当 type <> a 时,case 将 return 为空值。count() 不计算空值。)

SELECT COUNT(case when TYPE = A then 1 end) * 1.0 / COUNT(*)
FROM dataset

编辑:

受其他答案的启发,我决定 运行 进行一些性能测试。这里使用的 table tx 有数百万行的 10。列 c2 已编入索引,并且在 table.

中随机放置了数百个不同的值

查询 1:

select count(case when c2 = 'A' then 1 end) * 1.0 / count(*) from tx;

Direct I/O count      :      83067
Buffered I/O count    :          0
Page faults           :          3
CPU time     (seconds):      77.18
Elapsed time (seconds):      77.17

查询 2:

select avg(case when c2 = 'A' then 1.0 else 0.0 end) from tx;

Direct I/O count      :      83067
Buffered I/O count    :          0
Page faults           :          0
CPU time     (seconds):      84.90
Elapsed time (seconds):      84.90

查询 3:

select (select count(*) from tx where c2 = 'A') * 1.0 /
          (select count(*) from tx)
from onerow_table;

Direct I/O count      :      86204
Buffered I/O count    :          0
Page faults           :          2
CPU time     (seconds):       3.45
Elapsed time (seconds):       3.45

PS。 MS SQL 服务器上没有 运行。

使用条件聚合:求和 1.0 会得到一个未转换为 int 0 或 1 的百分比。

select sum(case when type='a' then 1.0 else 0 end)/count(*)
from t

测试设置:http://rextester.com/GXN95560

create table t (Machine int, Type char(1), Value int)
insert into t values
 (1,'A',11)
,(1,'B',32)
,(2,'A',23)
,(3,'A',1 )
,(4,'B',23)
,(4,'B',31)
,(5,'B',56)
,(6,'A',12)

select sum(case when type='a' then 1.0 else 0 end)/count(*)
from t

returns: 0.500000

SELECT COUNT(case when TYPE = 'a' then 1 end) / COUNT(*)
FROM t

returns: 0

select 
cast((sum(case when Type='A' then 1 else 0 end)) as float)/cast(Count(Type)) as float)
from dataset

这是戈登几周前展示的一个小技巧。 (似乎找不到 link)

Declare @YourTable table (Machine int, Type char(1), Value int)
insert into @YourTable values
 (1,'A',11)
,(1,'B',32)
,(2,'A',23)
,(3,'A',1 )
,(4,'B',23)
,(4,'B',31)
,(5,'B',56)
,(6,'A',12)

select avg(case when type='a' then 1.0 else 0 end)
from @YourTable

Returns

0.500000