将前5个元素分布在行和列上

时间:2016-04-22 05:21:30

标签: sql tsql sql-server-2012

在此表中使用T-SQL:

+-----+------+------+------+-----+
| 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 |
+-----+------+------+------+-----+

我需要计算所有行和列的TOP 3名称(按TotalCount DESC排序),适用于3个年龄组:0-17,18-49,50-100。另外,如何忽略结果中的 NULLS

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

仅1个年龄组的输出:18-49看起来像这样:

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

2 个答案:

答案 0 :(得分:3)

您需要首先取消对表格的删除,然后排除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

使用CROSS APPLYVALUES

的非文字技术

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

答案 1 :(得分:0)

您可以查看以下multiple-CTE SQL select语句 使用Row_Number() with Partition By子句对按年龄分类的每个组中的记录进行排序

    /*
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