SQL计数行中的非空单元格和按范围分组

时间:2018-01-29 19:12:08

标签: sql sql-server

我在main table中有一些数据:

| id | Attendance              | Accountability          | Respect                    |   |
|----|-------------------------|-------------------------|----------------------------|---|
| 1  | John was always on time | John is accountable     | John is always respectful  |   |
| 2  | Ann never missed a day  | Ann is very accountable |                            |   |
| 3  |                         |                         | Dan was very disrespectful |   |

我需要计算每行的非空单元格数,然后排序到范围。

示例:

首先计算非空单元格。

| id | Non-empty |
|----|-----------|
| 1  | 3         | # Row 1 has 3 comments
| 2  | 2         | # Row 2 has 2 comments and 1 empty cell
| 3  | 1         | # Row 3 has 1 comment and 2 empty cells
  

我们将此结果称为“表A”

然后根据留下的评论范围创建分组。 这是最终结果。

| id | Range        | Count |
|----|--------------|-------|
| 1  | 1-2 comments | 2     | # 2 rows have between 1 and 2 comments
| 2  | 3-4 comments | 1     | # 1 row has between 3 and 4 comments
| 3  | 5+ comments  | 0     | # 0 rows have more than 5 comments
  

我们将此结果称为“表B”

我做了什么

select 
  case 
    when Non-empty between 1 and 2 then '1-2 comments'
    when Non-empty between 3 and 4 then '3-4 comments'
    else then '5+ comments'
  end as `Range`,
 count(1) as `Count`
from `Table A`
group by `Range`
  

此查询应生成表A中的表B

我需要什么

从主表生成表B的单个SQL查询。

所以,我想我需要一个可以生成表A的查询,然后将它与上面的查询结合起来。

如果有更简单的方法从主表中获取表B,那么我欢迎它!

3 个答案:

答案 0 :(得分:2)

{{1}}

答案 1 :(得分:0)

在这个例子中,我使用了:

  • Case Expression - 识别非空单元格
  • BetweenSum运营商 - 获取范围和行数
  • Unpivot - 将表值表达式更改为另一个表

        --- Source
        CREATE TABLE Main
            (
              id INT ,
              attendance VARCHAR(254) ,
              Accountability VARCHAR(254) ,
              Respect VARCHAR(254)
            )
    
        INSERT  INTO Main
                ( id, attendance, accountability, respect )
        VALUES  ( 1, 'John was always on time', 'John is accountable',
                  'John is always respectful' ),
                ( 2, 'Ann never missed a day', 'Ann is very accountable', NULL ),
                ( 3, NULL, NULL, 'Dan was very disrespectful' )
    
    
        --- Query
        SELECT  ROW_NUMBER() OVER(ORDER BY col) id,
                col [range],
                val [count]
        FROM    ( SELECT    SUM(CASE WHEN ctr BETWEEN 1 AND 2 THEN 1
                                     ELSE 0
                                END) [1-2 comments] ,
                            SUM(CASE WHEN ctr BETWEEN 3 AND 4 THEN 1
                                     ELSE 0
                                END) [3-4 comments] ,
                            SUM(CASE WHEN ctr >= 5 THEN 1
                                     ELSE 0
                                END) [5+ comments]
                  FROM      ( SELECT    attendance + Accountability + Respect [ctr]
                              FROM      ( SELECT    CASE WHEN attendance IS NOT NULL
                                                              OR attendance <> ''
                                                         THEN 1
                                                         ELSE 0
                                                    END attendance ,
                                                    CASE WHEN Accountability IS NOT NULL
                                                              OR Accountability <> ''
                                                         THEN 1
                                                         ELSE 0
                                                    END Accountability ,
                                                    CASE WHEN Respect IS NOT NULL
                                                              OR Respect <> '' THEN 1
                                                         ELSE 0
                                                    END Respect
                                          FROM      Main
                                        ) T
                            ) Tmain
                ) TBL UNPIVOT( val FOR col IN ( [1-2 comments], [3-4 comments],
                                                [5+ comments] ) ) UPVT
    
    
    
        DROP TABLE Main
    

结果

    id                   range               count
    -------------------- ------------------- -----------
    1                    1-2 comments        2
    2                    3-4 comments        1
    3                    5+ comments         0

    (3 row(s) affected)

答案 2 :(得分:0)

这是对我有用的最终查询。

谢谢你@flip!你的回答让我最接近。

SELECT
    case 
        when comments between 1 and 2 then '1-2 comments'
        when comments between 3 and 4 then '3-4 comments'
        else '5+ comments'
    end as `Range`,
    count(1) as `Count` 
FROM( 
    SELECT id, 
        SUM(IF(Respect != '', 1, 0)) +
        SUM(IF(Accountability != '', 1, 0)) + 
        SUM(IF(Attendance != '', 1, 0))
    FROM `main table` 
    GROUP BY id
)AS T GROUP BY `Range`;