SQL 创建垂直直方图

SQL 创建垂直直方图,你想生成一个从下向上增长的直方图。例如,你希望以垂直直方图的方式显示每个部门的员工人数,每个 * 代表一个员工。你希望返回如下所示的结果集。

SQL 创建垂直直方图 问题描述

你想生成一个从下向上增长的直方图。例如,你希望以垂直直方图的方式显示每个部门的员工人数,每个 * 代表一个员工。你希望返回如下所示的结果集。

D10 D20 D30
--- --- ---
        *
    *   *
    *   *
*   *   *
*   *   *
*   *   *

SQL 创建垂直直方图 解决方案

我们将以 12.2 节中的方法为基础解决本问题。
DB2、Oracle 和 SQL Server
使用窗口函数 ROW_NUMBER OVER 为每个 DEPTNO 的每一个 * 生成唯一的序号。使用聚合函数 MAX 变换结果集,并针对 ROW_NUMBER OVER 函数的返回值执行 GROUP BY。SQL Server 用户不要在该 ORDER BY 子句中使用 DESC

 1  select max(deptno_10) d10,
 2         max(deptno_20) d20,
 3         max(deptno_30) d30
 4    from (
 5  select row_number()over(partition by deptno order by empno) rn,
 6         case when deptno=10 then '*' else null end deptno_10,
 7         case when deptno=20 then '*' else null end deptno_20,
 8         case when deptno=30 then '*' else null end deptno_30
 9    from emp
10         ) x
11   group by rn
12   order by 1 desc, 2 desc, 3 desc

PostgreSQLMySQL
使用标量子查询为每个 DEPTNO 的每一个 * 生成唯一的序号。针对内嵌视图 X 的返回值调用聚合函数 MAX,同时也针对 RNK 执行 GROUP BY 以实现结果集变换。MySQL 用户不要在 ORDER BY 子句中使用 DESC

 1  select max(deptno_10) as d10,
 2         max(deptno_20) as d20,
 3         max(deptno_30) as d30
 4    from (
 5  select case when e.deptno=10 then '*' else null end deptno_10,
 6         case when e.deptno=20 then '*' else null end deptno_20,
 7         case when e.deptno=30 then '*' else null end deptno_30,
 8         (select count(*) from emp d
 9           where e.deptno=d.deptno and e.empno < d.empno ) as rnk
10    from emp e
11         ) x
12   group by rnk
13   order by 1 desc, 2 desc, 3 desc

SQL 创建垂直直方图 扩展知识

DB2、Oracle 和 SQL Server
首先使用窗口函数 ROW_NUMBER 为每个 DEPTNO 的每一个 * 生成唯一的序号。使用 CASE 表达式为每个部门的每个员工返回一个 *

select row_number()over(partition by deptno order by empno) rn,
       case when deptno=10 then '*' else null end deptno_10,
       case when deptno=20 then '*' else null end deptno_20,
       case when deptno=30 then '*' else null end deptno_30
  from emp
 
RN DEPTNO_10  DEPTNO_20  DEPTNO_30
-- ---------- ---------- ---------
1 *
2 *
3 *
1             *
2             *
3             *
4             *
5             *
1                        *
2                        *
3                        *
4                        *
5                        *
6                        *

下一步也是最后一步,针对每个 CASE 表达式调用聚合函数 MAX,并基于 RN 分组剔除掉 Null 值。以 ASCDESC 方式排序取决于数据库如何对 Null 值排序。

select max(deptno_10) d10,
       max(deptno_20) d20,
       max(deptno_30) d30
  from (
select row_number()over(partition by deptno order by empno) rn,
       case when deptno=10 then '*' else null end deptno_10,
       case when deptno=20 then '*' else null end deptno_20,
       case when deptno=30 then '*' else null end deptno_30
  from emp
       ) x
 group by rn
 order by 1 desc, 2 desc, 3 desc
 
D10 D20 D30
--- --- ---
        *
    *   *
    *   *
*   *   *
*   *   *
*   *   *

PostgreSQL 和 MySQL
首先,使用标量子查询为每个 DEPTNO 的每一个 * 生成唯一的序号。该标量子查询基于 EMPNO 为每个 DEPTNO 的员工生成序号,因此不可能有重复项。使用 CASE 表达式为每个部门的每一个员工返回一个 *

select case when e.deptno=10 then '*' else null end deptno_10,
       case when e.deptno=20 then '*' else null end deptno_20,
       case when e.deptno=30 then '*' else null end deptno_30,
       (select count(*) from emp d
         where e.deptno=d.deptno and e.empno < d.empno ) as rnk
  from emp e
 
DEPTNO_10  DEPTNO_20  DEPTNO_30         RNK
---------- ---------- ---------- ----------
           *                              4
                      *                   5
                      *                   4
           *                              3
                      *                   3
                      *                   2
*                                         2
           *                              2
*                                         1
                      *                   1
           *                              1
                      *                   0
           *                              0
*                                         0

然后,针对每个 CASE 表达式调用聚合函数 MAX。这样一来,按照 RNK 分组后就能够从结果集中剔除掉 Null 值了。以 ASCDESC 方式排序取决于数据库如何对 Null 值排序。

select max(deptno_10) as d10,
       max(deptno_20) as d20,
       max(deptno_30) as d30
  from (
select case when e.deptno=10 then '*' else null end deptno_10,
       case when e.deptno=20 then '*' else null end deptno_20,
       case when e.deptno=30 then '*' else null end deptno_30,
       (select count(*) from emp d
         where e.deptno=d.deptno and e.empno < d.empno ) as rnk
  from emp e
       ) x
 group by rnk
 order by 1 desc, 2 desc, 3 desc
 
D10 D20 D30
--- --- ---
        *
    *   *
    *   *
*   *   *
*   *   *
*   *   *

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程