2016-04-22 28 views
2

使用T-SQL此表:计数前5个元素分布在行和列

+-----+------+------+------+-----+ 
| No. | Col1 | Col2 | Col3 | Age | 
+-----+------+------+------+-----+ 
| 1 | e | a | o | 5 | 
| 2 | f | b | a | 34 | 
| 3 | a | NULL | b | 22 | 
| 4 | b | c | a | 55 | 
| 5 | b | a | b | 19 | 
+-----+------+------+------+-----+ 

我需要统计的前3名(由TOTALCOUNT DESC有序)对所有的行和列,为3岁组:0-17,18-49,50-100。另外,如何从结果中忽略NULLS

如果可能的话,我怎么也可以将所有3个年龄组的结果合并为一个输出表以获得9个结果(TOP 3 x 3年龄组)?

输出只有1年龄:18-49应该是这样的:

+------+------------+ 
| Name | TotalCount | 
+------+------------+ 
| b |   4 | 
| a |   3 | 
| f |   1 | 
+------+------------+ 

回答

3

请先UNPIVOT你的表,然后排除NULL秒。然后做一个简单的COUNT(*)

WITH CteUnpivot(Name, Age) AS(
    SELECT x.* 
    FROM tbl t 
    CROSS APPLY (VALUES 
     (col1, Age), 
     (col2, Age), 
     (col3, Age) 
    ) x(Name, Age) 
    WHERE x.Name IS NOT NULL 
) 
SELECT TOP 3 
    Name, COUNT(*) AS TotalCount 
FROM CteUnpivot 
WHERE Age BETWEEN 18 AND 49 
GROUP BY Name 
ORDER BY COUNT(*) DESC 

ONLINE DEMO


如果你想获得TOP 3各年龄组:

WITH CteUnpivot(Name, Age) AS(
    SELECT x.* 
    FROM tbl t 
    CROSS APPLY (VALUES 
     (col1, Age), 
     (col2, Age), 
     (col3, Age) 
    ) x(Name, Age) 
    WHERE x.Name IS NOT NULL 
), 
CteRn AS (
    SELECT 
     AgeGroup = 
      CASE 
       WHEN Age BETWEEN 0 AND 17 THEN '0-17' 
       WHEN Age BETWEEN 18 AND 49 THEN '18-49' 
       WHEN Age BETWEEN 50 AND 100 THEN '50-100' 
      END, 
     Name, 
     COUNT(*) AS TotalCount 
    FROM CteUnpivot 
    GROUP BY 
     CASE 
      WHEN Age BETWEEN 0 AND 17 THEN '0-17' 
      WHEN Age BETWEEN 18 AND 49 THEN '18-49' 
      WHEN Age BETWEEN 50 AND 100 THEN '50-100' 
     END, 
     Name 
) 
SELECT 
    AgeGroup, Name, TotalCount 
FROM(
    SELECT *, 
     rn = ROW_NUMBER() OVER(PARTITION BY AgeGroup, Name ORDER BY TotalCount DESC) 
    FROM CteRn 
) t 
WHERE rn <= 3; 

ONLINE DEMO


的unpivot的技术使用CROSS APPLYVALUES

An Alternative (Better?) Method to UNPIVOT (SQL Spackle) by Dwain Camps

+0

有趣的分类各组内检查以下multiple-CTE SQL SELECT语句用于 Row_Number() with Partition By条款顺序记录'CROSS APPLY'和'VALUES'的用法 – ughai

+2

@ughai从Dwain得到Camp的[文章](http://www.sqlservercentral.com/articles/CROSS+APPLY+VALUES+UNPIVOT/91234/)。 –

0

您可以通过年龄

/* 
CREATE TABLE tblAges(
    [No]  Int, 
    Col1 VarChar(10), 
    Col2 VarChar(10), 
    Col3 VarChar(10), 
    Age  SmallInt 
) 
INSERT INTO tblAges VALUES 
(1, 'e', 'a',  'o', 5), 
(2, 'f', 'b',  'a', 34), 
(3, 'a', NULL,  'b', 22), 
(4, 'b', 'c',  'a', 55), 
(5, 'b', 'a',  'b', 19); 
*/ 
;with cte as (
    select 
     col1 as col, Age 
    from tblAges 
    union all 
    select 
     col2, Age 
    from tblAges 
    union all 
    select 
     col3, Age 
    from tblAges 
), cte2 as (
    select 
     col, 
     case 
      when age < 18 then '0-17' 
      when age < 50 then '18-49' 
      else '50-100' 
     end as grup 
    from cte 
    where col is not null 
), cte3 as (
select 
    grup, 
    col, 
    count(grup) cnt 
from cte2 
group by 
    grup, 
    col 
) 
select * from (
select 
grup, col, cnt, ROW_NUMBER() over (partition by grup order by cnt desc) cnt_grp 
from cte3 
) t 
where cnt_grp <= 3 
order by grup, cnt