2012-10-31 76 views
3

我試圖創建此概要統計數據表,從該表中年齡間隔與SQL

PersonID | Age | Sex 
---------------------------- 
    A  | 43 | F 
    B  | 22 | F 
    C  | 65 | M 
    D  | 33 | F 
    E  | 28 | M 

計數在每個類別

Agegroup | All | Female | Male 
------------------------------------------------ 
All  | 560594 | 34324 | 234244 
< 20  | 4324 |  545  | 3456 
20 - 30 | 76766 |  3424 | 32428 
30 - 40 | 36766 |  764  | 82427 
40 - 50 | 46766 |  4324 | 72422 
50 - 60 | 66766 |  3424 | 52424 
> 60  | 76766 | 43424 | 12423 

的個體數列的統計資料這甚至可能「一氣呵成」與SQL?我嘗試了這一點,但它不是真正的走到一起..

SELECT SUM(CASE WHEN Age < 20 THEN 1 ELSE 0 END) AS [Under 20], 
    SUM(CASE WHEN Age BETWEEN 20 AND 30 THEN 1 ELSE 0 END) AS [20-30], 
    SUM(CASE WHEN Age BETWEEN 30 AND 40 THEN 1 ELSE 0 END) AS [30-40] 
FROM Persons 
+0

你在使用MSSQL,ORACEL,MySQL的? – Arion

+0

對,sql服務器 – jenswirf

+0

@wije - 在什麼樣的年齡組你會期望30歲的人? '20-30','30-40'還是兩者兼而有之? –

回答

4

我相信下面是實現這一目標的最簡單的方法,並同時獲得該行回來,即使沒有在該年齡段內的人。此外由於Sex只有2個可能的值,您可以使用NULLIF而不是案例表達式。

SELECT [Agegroup] = Name, 
     [All] = COUNT(Person.PersonID), 
     [Female] = COUNT(NULLIF(Person.Sex, 'M')), 
     [Male] = COUNT(NULLIF(Person.Sex, 'F')) 
FROM (VALUES 
      (0, 1000, 'All'), 
      (0, 20, '< 20'), 
      (20, 30, '20 - 30'), 
      (30, 40, '30 - 40'), 
      (40, 50, '40 - 40'), 
      (50, 60, '50 - 40'), 
      (60, 1000, '> 60') 
     ) AgeRange (MinValue, MaxValue, Name) 
     LEFT JOIN Person 
      ON Person.Age >= AgeRange.MinValue 
      AND Person.Age < AgeRange.Maxvalue 
GROUP BY AgeRange.Name, AgeRange.MinValue, AgeRange.Maxvalue 
ORDER BY AgeRange.MinValue, AgeRange.MaxValue DESC 

Example on SQL Fiddle

0
select 'All' as [Age Group] 
.  count(*) as [All], 
,  sum(case Sex when 'F' then 1 end) as Female 
,  sum(case Sex when 'M' then 1 end) as Male 
from Persons 
union all 
select '< 20' as [Age Group] 
.  count(*) as [All], 
,  sum(case Sex when 'F' then 1 end) as Female 
,  sum(case Sex when 'M' then 1 end) as Male 
from Persons 
where Age < 20 
union all 
select '20 - 30' as [Age Group] 
.  count(*) as [All], 
,  sum(case Sex when 'F' then 1 end) as Female 
,  sum(case Sex when 'M' then 1 end) as Male 
from Persons 
where 20 <= Age and Age < 30 
union all 
... 
2

也許是這樣的:

DECLARE @T TABLE(PersonID VARCHAR(5), Age INT,Sex VARCHAR(5)) 

INSERT INTO @T 
VALUES 
    ('A',43,'F'), 
    ('B',22 ,'F'), 
    ('C ',65,'M'), 
    ('D',33,'F'), 
    ('E',28,'M') 

SQL

SELECT 
    'All' AS Agegroup, 
    COUNT(*) AS [All], 
    SUM(CASE WHEN tbl.Sex='F' THEN 1 ELSE 0 END) AS Female, 
    SUM(CASE WHEN tbl.Sex='M' THEN 1 ELSE 0 END) AS Male 
FROM 
    @T AS tbl 
UNION ALL 
SELECT 
    tbl.Agegroup, 
    COUNT(*) AS [All], 
    SUM(CASE WHEN tbl.Sex='F' THEN 1 ELSE 0 END) AS Female, 
    SUM(CASE WHEN tbl.Sex='M' THEN 1 ELSE 0 END) AS Male 
FROM 
(
    SELECT 
     (
      CASE 
      WHEN Age BETWEEN 0 and 20 
      THEN '< 20' 
      WHEN Age BETWEEN 20 and 30 
      THEN '20 - 30' 
      WHEN Age BETWEEN 30 and 40 
      THEN '30 - 40' 
      WHEN Age BETWEEN 40 and 50 
      THEN '40 - 50' 
      WHEN Age BETWEEN 50 and 60 
      THEN '50 - 60' 
      WHEN Age> 60 
      THEN '> 60' 
      END 
     ) AS Agegroup, 
     t.Age, 
     t.Sex 
    FROM 
     @T AS t 
) AS tbl 
GROUP BY 
    tbl.Agegroup 
2

你最好的方式是創建一個年齡範圍表(或下面例子中的虛擬表)並加入到該表中,然後轉動結果以將結果轉換爲列狀R M。

select range as AgeGroup, m as Male, F as Female, m+f as [all] 
from 
( 
    select PersonID, range, sex 
    from 
    (
     select 'all' as range, 0 as minval, 200 as maxval 
     union select '<20',0,19 
     union select '20-29',20,29 
     -- etc.... 
    ) ranges 
     left join 
    yourtable t 
     on t.age between minval and maxval 
) src 
pivot 
    (count(personid) for sex in ([m],[f])) p 
1

試試這個:

;with Age_range as(
select '<20' as age union all 
select '20 - 30' as age union all 
select '30 - 40' as age union all 
select '40 - 50' as age union all 
select '50 - 60' as age union all 
select '>60' as age 
), 
cte as(
select [Sex], 
sum(case when [Age]<20 then 1 else 0 end) as '<20' , 
sum(case when [Age]between 20 and 29 then 1 else 0 end) as '20 - 30', 
sum(case when [Age]between 30 and 39 then 1 else 0 end) as '30 - 40', 
sum(case when [Age]between 40 and 49 then 1 else 0 end) as '40 - 50', 
sum(case when [Age]between 50 and 59 then 1 else 0 end) as '50 - 60', 
sum(case when [Age]>=60 then 1 else 0 end) as '>60' 
from Persons 
group by [Sex]), 
cte1 as(select Sex,'<20' as cnt from cte where [<20]>0 union all 
select Sex,'20 - 30' as cnt from cte where [20 - 30]>0 union all 
select Sex,'30 - 40' as cnt from cte where [30 - 40]>0 union all 
select Sex,'40 - 50' as cnt from cte where [40 - 50]>0 union all 
select Sex,'50 - 60' as cnt from cte where [50 - 60]>0 union all 
select Sex,'>60' as cnt from cte where [>60]>0) 
select A.age, 
     COUNT(case when sex in ('M','F') then 1 end) as [All], 
     COUNT(case when sex='F' then 1 end) as Female, 
     COUNT(case when sex='M' then 1 end) as Male 
    from Age_range A left join cte1 C 
    on A.age=C.cnt 
    group by A.age 


SQL Fiddle Demo