在SQL中聚合多个列

时间:2012-03-09 02:59:33

标签: sql sql-server pivot aggregate-functions

假设我有一个类似于以下内容的表

id | location | dateHired | dateRehired | dateTerminated
1  | 1        | 10/1/2011 | NULL        | 12/1/2011
2  | 1        | 10/3/2011 | 11/1/2011   | 12/31/2011
3  | 5        | 10/5/2011 | NULL        | NULL
4  | 5        | 10/5/2011 | NULL        | NULL
5  | 7        | 11/5/2011 | NULL        | 12/1/2011
6  | 10       | 11/2/2011 | NULL        | NULL

我希望将其浓缩成一个汇总表,以便:

location | date        | hires  | rehires |   terms
1        |  10/1/2011  |   1    |    0    |     0
1        |  10/3/2011  |   1    |    0    |     0
1        |  11/1/2011  |   0    |    1    |     0
1        |  12/1/2011  |   0    |    0    |     1
1        |  12/31/2011 |   1    |    0    |     0
5        |  10/5/2011  |   2    |    0    |     0

- SQL会是什么样子?我认为它会产生一些影响:

SELECT
  e.location
  , -- ?
  ,SUM(CASE WHEN e.dateHired IS NOT NULL THEN 1 ELSE 0 END) AS Hires
  ,SUM(CASE WHEN e.dateRehired IS NOT NULL THEN 1 ELSE 0 END) As Rehires
  ,SUM(CASE WHEN e.dateTerminated IS NOT NULL THEN 1 ELSE 0 END) As Terms
FROM
  Employment e
GROUP BY
  e.Location
  ,--?

但是,如果那是完全正确的话我不是真的很敏感吗?

编辑 - 这适用于SQL 2008 R2。

此外,

日期列上的INNER JOIN假定所有三个类别都有值,这是假的;这是我试图解决的原始问题。我在考虑像COALESCE这样的东西,但这也没有意义。

3 个答案:

答案 0 :(得分:1)

我确信可能有一种更简单,更优雅的方法来解决这个问题。然而,这是我能想到的最简单,最快捷的方法。

CREATE TABLE #Temp
(
    Location INT,
    Date DATETIME,
    HireCount INT,
    RehireCount INT,
    DateTerminatedCount INT
)

--This will keep us from having to do an insert if does not already exist
INSERT INTO #Temp (Location, Date)
SELECT DISTINCT Location, DateHired FROM Employment
UNION
SELECT DISTINCT Location, DateRehired FROM Employment
UNION
SELECT DISTINCT Location, DateTerminated FROM Employment

UPDATE #Temp
SET HireCount = Hired.HireCount
FROM #Temp
JOIN
(
    SELECT Location, DateHired AS Date, SUM(*) AS HireCount 
    FROM Employment
    GROUP BY Location, DateHired
) AS Hired

UPDATE #Temp
SET RehireCount= Rehire.RehireCount
FROM #Temp
JOIN
(
    SELECT Location, DateRehired AS Date, SUM(*) AS RehireCount
    FROM Employment
    GROUP BY Location, DateRehired
) AS Rehire
    ON Rehire.Location = #Temp.Location AND Rehire.Date = #Temp.Date

UPDATE #Temp
SET DateTerminatedCount = Terminated.DateTerminatedCount
FROM #Temp
JOIN
(
    SELECT Location, DateTerminated AS Date, SUM(*) AS DateTerminatedCount
    FROM Employment
    GROUP BY Location, DateTerminated
) AS Terminated
    ON Terminated.Location = #Temp.Location AND Terminated.Date = #Temp.Date

SELECT * FROM #Temp

答案 1 :(得分:1)

如下:

with dates as (
    select distinct location, d from (
        select location, dateHired as [d]
        from tbl
        where dateHired is not null

        union all

        select location, dateRehired 
        from tbl
        where dateRehired is not null

        union all  

        select location, dateTerminated
        from tbl
        where dateTerminated is not null
    )
)

select location, [d],
    (
        select count(*) 
        from tbl 
        where location = dates.location 
            and dateHired = dates.[d]
    ) as hires,
    (
        select count(*) 
        from tbl 
        where location = dates.location 
            and dateRehired = dates.[d]
    ) as rehires,
    (
        select count(*) 
        from tbl 
        where location = dates.location 
            and dateTerminated = dates.[d]
    ) as terms
from dates

我没有方便的SQL服务器,或者我会测试它。

答案 2 :(得分:0)

SELECT * FROM  
(SELECT location, dateHired as date, COUNT(1) as hires FROM mytable GROUP BY location, date) H  
INNER JOIN  
(SELECT location, dateReHired as date, COUNT(1) as rehires FROM mytable GROUP BY location, date) R ON H.location = R.location AND H.dateHired = R.dateRehired  
INNER JOIN 
(SELECT location, dateTerminated as date, COUNT(1) as terminated FROM mytable GROUP BY  location, date) T  
ON H.location = T.location AND H.dateHired = T.dateTerminated