Counting values in a column separately

2019-07-14 07:01发布

问题:

I have a table in my database with the following structure.

ID   COMPANY_ID  Status
-----------------------
1       10         1 
2       10         2
3       12         2 
4       12         2 
5       12         1 
6       13         3 
7       14         3 
8       14         3 
9       10         1
10      10         2

I want to group my results on company ID and count each status and list them as separate columns.

i.e.

COMPANY_ID   Status 1   Status 2   Status 3
-------------------------------------------
10             2           2           0
12             1           2           0
13             0           0           1
14             0           0           2

My question is how do I get the results above from my table? and probably join in with the company table.

Tried several possibilities, but didn't get the results.

回答1:

This type of data transformation is known as a PIVOT. There are several ways that you are pivot the data.

You can use an aggregate function with a CASE expression:

select company_id,
  sum(case when status = 1 then 1 else 0 end) status1,
  sum(case when status = 2 then 1 else 0 end) status2,
  sum(case when status = 3 then 1 else 0 end) status3
from yourtable
group by company_id;

See SQL Fiddle with Demo

Starting in SQL Server 2005+ you can use the PIVOT function:

select company_id,
  [1] as Status1,
  [2] as Status2,
  [3] as Status3
from
(
  select company_id, status
  from yourtable
)src
pivot
(
  count(status)
  for status in ([1], [2], [3])
) piv

See SQL Fiddle with Demo.

The two versions above work well if you have a known number of values to transform into columns. But if it is unknown, then you can use dynamic SQL to generate the result:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('Status'+cast(status as varchar(10))) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT company_id,' + @cols + ' from 
             (
                select company_id, ''Status''+cast(status as varchar(10)) Status
                from yourtable
            ) x
            pivot 
            (
                count(Status)
                for Status in (' + @cols + ')
            ) p '

execute(@query)

See SQL Fiddle with Demo.

All give the result:

| COMPANY_ID | STATUS1 | STATUS2 | STATUS3 |
--------------------------------------------
|         10 |       2 |       2 |       0 |
|         12 |       1 |       2 |       0 |
|         13 |       0 |       0 |       1 |
|         14 |       0 |       0 |       2 |


回答2:

select  company_id
,       count(case when status = 1 then 1 end) as [Status 1]
,       count(case when status = 2 then 1 end) as [Status 2]
,       count(case when status = 3 then 1 end) as [Status 3]
from    YourTable
group by
        company_id