使用 SQL 創(chuàng)建柱狀圖,是真的嗎?
作者: 不剪發(fā)的Tony老師
畢業(yè)于北京航空航天大學(xué),十多年數(shù)據(jù)庫(kù)管理與開(kāi)發(fā)經(jīng)驗(yàn),目前在一家全球性的金融公司從事數(shù)據(jù)庫(kù)架構(gòu)設(shè)計(jì)。CSDN學(xué)院簽約講師以及GitChat專欄作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net
今天我們介紹如何使用 SQL 語(yǔ)句創(chuàng)建水平柱狀圖和垂直柱狀圖,使用的功能包括分組聚合、字符串函數(shù)、CASE 條件表達(dá)式以及窗口函數(shù)。本文描述的方法支持但不限于 Oracle、MySQL/MariaDB、Microsoft SQL Server、PostgreSQL 以及 SQLite 等數(shù)據(jù)庫(kù)。
水平柱狀圖
員工表(employee)中存儲(chǔ)了每個(gè)部門中的員工信息,部門表(department)中存儲(chǔ)了部門的信息。假如我們想要統(tǒng)計(jì)每個(gè)部門的員工數(shù)量,并且以水平直方圖的形式進(jìn)行顯示。以下是 MySQL 數(shù)據(jù)庫(kù)中的實(shí)現(xiàn):
– MySQL/MariaDB
SELECT d.dept_name “部門名稱”,
count(e.emp_id) “員工數(shù)量”,
repeat(‘▇’, count(e.emp_id)) “柱狀圖”
FROM department d
LEFT JOIN employee e ON (d.dept_id = e.dept_id)
GROUP BY dept_name
ORDER BY count(*) DESC;
我們首先通過(guò)分組和 COUNT 聚合函數(shù)得到了每個(gè)部門的員工人數(shù),左外連接確保部門沒(méi)有員工時(shí)也會(huì)返回相應(yīng)的信息。然后我們通過(guò) repeat 函數(shù)創(chuàng)建一個(gè)基于員工人數(shù)的水平直方圖。最終查詢返回的結(jié)果如下:
對(duì)于其他數(shù)據(jù)庫(kù),實(shí)現(xiàn)的員工相同,只是需要替換相應(yīng)的字符串函數(shù):
– Microsoft SQL Server
SELECT d.dept_name “部門名稱”,
count(e.emp_id) “員工數(shù)量”,
replicate(‘▇’, count(e.emp_id)) “柱狀圖”
FROM department d
LEFT JOIN employee e ON (d.dept_id = e.dept_id)
GROUP BY dept_name
ORDER BY count(*) DESC;
– PostgreSQL
SELECT d.dept_name “部門名稱”,
count(e.emp_id) “員工數(shù)量”,
repeat(‘▇’, count(e.emp_id)::integer) “柱狀圖”
FROM department d
LEFT JOIN employee e ON (d.dept_id = e.dept_id)
GROUP BY dept_name
ORDER BY count(*) DESC;
– Oracle
SELECT d.dept_name “部門名稱”,
count(e.emp_id) “員工數(shù)量”,
lpad(‘▇’, count(e.emp_id), ‘▇’) “柱狀圖”
FROM department d
LEFT JOIN employee e ON (d.dept_id = e.dept_id)
GROUP BY dept_name
ORDER BY count(*) DESC;
– SQLite
SELECT d.dept_name “部門名稱”,
count(e.emp_id) “員工數(shù)量”,
replace(hex(zeroblob(count(e.emp_id))), ‘00’, ‘█’) “柱狀圖”
FROM department d
LEFT JOIN employee e ON (d.dept_id = e.dept_id)
GROUP BY dept_name
ORDER BY count(*) DESC;
對(duì)于 Microsoft SQL Server,我們可以使用 replicate 函數(shù)替換 repeat 函數(shù)。
對(duì)于 PostgreSQL,我們需要為 repeat 函數(shù)明確指定一個(gè) integer 類型的參數(shù)。
對(duì)于 Oracle,我們可以使用 lpad 函數(shù)替換 repeat 函數(shù)。另外,MySQL/MariaDB 和 PostgreSQL 也支持 lpad 函數(shù),也可以使用這種方式。
SQLite 不支持 repeat 函數(shù)或者替換的函數(shù),我們可以先利用 zeroblob 函數(shù)生成一個(gè)由 0x00 組成的 BLOB,然后通過(guò) replace 函數(shù)將其替換為柱狀圖。
垂直柱狀圖
如果我們將水平直方圖逆時(shí)針旋轉(zhuǎn) 90 度,就可以得到垂直柱狀圖。以下是 MySQL/MariaDB、Microsoft SQL Server 以及 SQLite 中的實(shí)現(xiàn):
– MySQL、Microsoft SQL Server以及SQLite
WITH d AS (
SELECT row_number() OVER (PARTITION BY dept_id ORDER BY emp_id) rn,
CASE WHEN dept_id=1 THEN ‘█’ END dept1,
CASE WHEN dept_id=2 THEN ‘█’ END dept2,
CASE WHEN dept_id=3 THEN ‘█’ END dept3,
CASE WHEN dept_id=4 THEN ‘█’ END dept4,
CASE WHEN dept_id=5 THEN ‘█’ END dept5,
CASE WHEN dept_id=6 THEN ‘█’ END dept6
FROM employee
)
SELECT min(dept1) “行政管理部”,
min(dept2) “人力資源部”,
min(dept3) “財(cái)務(wù)部”,
min(dept4) “研發(fā)部”,
min(dept5) “銷售部”,
min(dept6) “保衛(wèi)部”
FROM d
GROUP BY rn
ORDER BY 1, 2, 3, 4, 5, 6;
我們首先創(chuàng)建了一個(gè)通用表表達(dá)式(CTE),利用 row_number 窗口函數(shù)得到了每個(gè)員工在各自部門中的編號(hào),同時(shí)通過(guò) CASE 表達(dá)式將對(duì)應(yīng)的員工使用 █ 進(jìn)行表示,此時(shí)生成的數(shù)據(jù)如下。
rn | dept1 | dept2 | dept3 | dept4 | dept5 | dept6 |
---|---|---|---|---|---|---|
1 | █ | |||||
2 | █ | |||||
3 | █ | |||||
1 | █ | |||||
2 | █ | |||||
3 | █ | |||||
1 | █ | |||||
2 | █ | |||||
1 | █ | |||||
2 | █ | |||||
3 | █ | |||||
4 | █ | |||||
5 | █ | |||||
6 | █ | |||||
7 | █ | |||||
8 | █ | |||||
9 | █ | |||||
1 | █ | |||||
2 | █ | |||||
3 | █ | |||||
4 | █ | |||||
5 | █ | |||||
6 | █ | |||||
7 | █ | |||||
8 | █ |
??關(guān)于窗口函數(shù)的介紹和案例分析可以參考這篇文章和這篇文章。
??關(guān)于通用表表達(dá)式以及各種數(shù)據(jù)庫(kù)中的語(yǔ)法可以參考這篇文章,以及一個(gè)分析社交網(wǎng)絡(luò)關(guān)系的實(shí)戰(zhàn)案例。
- 1
- 2
最后我們?cè)谥鞑樵冋Z(yǔ)句中利用分組和 min 聚合函數(shù)創(chuàng)建一個(gè)基于員工人數(shù)的垂直柱狀圖。最終查詢返回的結(jié)果如下:
行政管理部 | 人力資源部 | 財(cái)務(wù)部 | 研發(fā)部 | 銷售部 | 保衛(wèi)部 |
---|
| | |█ |█ | |
| | |█ |█ | |
| | |█ |█ | |
| | |█ |█ | |
| | |█ |█ | |
| | |█ |█ | |
- 1
- 2
- 3
- 4
- 5
- 6
█ |█ | |█ |█ | |
█ |█ |█ |█ |█ | |
█ |█ |█ |█ |█ | |
對(duì)于 Oracle 和 PostgreSQL,查詢的實(shí)現(xiàn)和上面的語(yǔ)句幾乎相同,只需要將排序修改為降序即可:
– Oracle 和 PostgreSQ
WITH d AS (
SELECT row_number() OVER (PARTITION BY dept_id ORDER BY emp_id) rn,
CASE WHEN dept_id=1 THEN ‘█’ END dept1,
CASE WHEN dept_id=2 THEN ‘█’ END dept2,
CASE WHEN dept_id=3 THEN ‘█’ END dept3,
CASE WHEN dept_id=4 THEN ‘█’ END dept4,
CASE WHEN dept_id=5 THEN ‘█’ END dept5,
CASE WHEN dept_id=6 THEN ‘█’ END dept6
FROM employee
)
SELECT min(dept1) “行政管理部”,
min(dept2) “人力資源部”,
min(dept3) “財(cái)務(wù)部”,
min(dept4) “研發(fā)部”,
min(dept5) “銷售部”,
min(dept6) “保衛(wèi)部”
FROM d
GROUP BY rn
ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC, 5 DESC, 6 DESC;
總結(jié)
本文利用 SQL 中的分組聚合、字符串函數(shù)、CASE 條件表達(dá)式以及窗口函數(shù)等功能實(shí)現(xiàn)了水平柱狀圖和垂直柱狀圖。