如果你經常需要寫大量的 SQL腳本
來進行數(shù)據分析工作闺魏,那你可能值得擁有這款神器:
https://github.com/taojy123/sqlx
SQLx
意為 SQL Extension
史辙,強大的 SQL 語法拓展橙困,目標是打造 "易讀易寫 方便維護" 的 SQL 腳本。
應用場景
假設有一張商品價目表(product)漂彤,每天價格變動的商品都會更新報價。
例如,蘋果的最新價格為 10 元, 因為蘋果最新的一次報價是在 20191211, 當時價格為 10 元洞渔。
name(商品名稱) | price(價格) | date(報價日期) |
---|---|---|
蘋果 | 15 | 20191208 |
香蕉 | 18 | 20191208 |
橘子 | 12 | 20191208 |
香蕉 | 16 | 20191209 |
橘子 | 11 | 20191209 |
蘋果 | 11 | 20191210 |
橘子 | 13 | 20191210 |
蘋果 | 10 | 20191211 |
香蕉 | 22 | 20191211 |
橘子 | 14 | 20191212 |
現(xiàn)在要求通過 sql 統(tǒng)計出 20191212 這天的平均價格 比 20191209 那天漲了多少
?
正常情況下我們可能會寫出這樣的 sql
SELECT
a1.avg_price AS `20191209 平均價格`,
a2.avg_price AS `20191212 平均價格`,
(a2.avg_price - a1.avg_price) AS `漲價金額`
FROM
(
-- 求出各類別 20191209 前最后一次報價的平均價格
SELECT
avg(product.price) AS avg_price
FROM
(
-- 求出各商品在 20191209 前最后一次報價的日期
SELECT
name,
max(date) AS max_date
FROM
product
WHERE
date <= '20191209'
GROUP BY
name
) AS t1
LEFT JOIN product
ON t1.name = product.name AND t1.max_date = product.date
) AS a1
LEFT JOIN
(
-- 再求出各類別 20191212 前最后一次報價的平均價格
SELECT
avg(product.price) AS avg_price
FROM
(
-- 先求出各商品在 20191212 前最后一次報價的日期
SELECT
name,
max(date) AS max_date
FROM
product
WHERE
date <= '20191212'
GROUP BY
name
) AS t2
LEFT JOIN product
ON t2.name = product.name AND t2.max_date = product.date
) AS a2
ON true
得到統(tǒng)計結果如下:
20191209 平均價格 | 20191212 平均價格 | 漲價金額 |
---|---|---|
14.0000 | 15.3333 | 1.3333 |
傳統(tǒng)做法雖然得到的結果是正確的,但同時暴露出以下問題:
- 子查詢多層嵌套缚态,代碼可讀性極低
-
t1
t2
兩個子查詢內容基本一致磁椒,也就說我們要維護兩處相同的代碼 -
a1
a2
兩個子查詢也基本一致,并且其中相同的注釋我們要寫兩遍玫芦,感覺太"蠢"了 - 這只是個很簡單的示例浆熔,在實際工作中,針對更復雜的統(tǒng)計需求桥帆,代碼的復雜度將會以指數(shù)形式遞增
下面看看如何使用 sqlx 來解決上述問題:
func product_max_date(day)
-- 子查詢: 統(tǒng)計出各個商品在 {day} 前最后一次報價的日期
(
SELECT
name,
max(date) AS max_date
FROM
product
WHERE
date <= '{day}'
GROUP BY
name
)
end
func date_avg_price(day):
-- 子查詢: 統(tǒng)計出 {day} 這天各個類別的平均價格
(
SELECT
avg(product.price) AS avg_price
FROM
{product_max_date($day)} AS t1
LEFT JOIN product
ON t1.name = product.name AND t1.max_date = product.date
)
end
SELECT
a1.avg_price AS `20191209 平均價格`,
a2.avg_price AS `20191212 平均價格`,
(a2.avg_price - a1.avg_price) AS `漲價金額`
FROM
{date_avg_price(20191209)} AS a1
LEFT JOIN
{date_avg_price(20191212)} AS a2
ON true
優(yōu)勢非常明顯:
- 核心代碼是一段短小的
SELECT
医增,外加兩個子查詢的定義就搞定了,代碼邏輯清晰老虫,可讀性高 -
a1
a2
使用類似函數(shù)
的概念進行封裝叶骨,通過傳入不同的參數(shù)來生成不同的子查詢內容 - 相同邏輯的代碼片段只需要寫一遍,大大降低了代碼維護的工作量
- 使用 sqlx 提供的編譯工具或插件祈匙,可快速編譯成 sql 代碼忽刽,在數(shù)據庫中執(zhí)行結果一致
如何使用
先看一下 sqlx 的基本語法介紹,很簡單 5 分鐘就看明白學會了菊卷。
接下來就開始編寫你的 sqlx 腳本吧缔恳,保存文件時拓展名設為 .sqlx
然后下載 sqlx 的編譯工具,如果你使用 Windows 64位系統(tǒng)
可以直接下載 sqlx.exe 洁闰。雙擊運行歉甚,即可將當前目錄下的 sqlx 腳本文件一鍵編譯為 sql。
如果你使用 Sublime Text
編輯器扑眉,可以搜索下載 Sqlx Builder
插件來使用纸泄,更加方便赖钞。