一个写 SQL 的神器

如果你经常需要写大量的 SQL脚本 来进行数据分析工作,那你可能值得拥有这款神器:

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

现在要求通过 sql 统计出 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

得到统计结果如下:

20191209 平均价格 20191212 平均价格 涨价金额
14.0000 15.3333 1.3333

传统做法虽然得到的结果是正确的,但同时暴露出以下问题:

  1. 子查询多层嵌套,代码可读性极低
  2. t1 t2 两个子查询内容基本一致,也就说我们要维护两处相同的代码
  3. a1 a2 两个子查询也基本一致,并且其中相同的注释我们要写两遍,感觉太"蠢"了
  4. 这只是个很简单的示例,在实际工作中,针对更复杂的统计需求,代码的复杂度将会以指数形式递增

下面看看如何使用 sqlx 来解决上述问题:

func product_max_date(day)
    -- 子查询: 统计出各个商品在 {day} 前最后一次报价的日期
    (
        SELECT
            name,
            max(date) AS max_date
        FROM
            product
        WHERE
            date <= '{day}'
        GROUP BY
            name
    )
end

func date_avg_price(day):
    -- 子查询: 统计出 {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

优势非常明显:

  1. 核心代码是一段短小的 SELECT,外加两个子查询的定义就搞定了,代码逻辑清晰,可读性高
  2. a1 a2 使用类似 函数 的概念进行封装,通过传入不同的参数来生成不同的子查询内容
  3. 相同逻辑的代码片段只需要写一遍,大大降低了代码维护的工作量
  4. 使用 sqlx 提供的编译工具或插件,可快速编译成 sql 代码,在数据库中执行结果一致

如何使用

先看一下 sqlx 的基本语法介绍,很简单 5 分钟就看明白学会了。

接下来就开始编写你的 sqlx 脚本吧,保存文件时拓展名设为 .sqlx

然后下载 sqlx 的编译工具,如果你使用 Windows 64位系统 可以直接下载 sqlx.exe 。双击运行,即可将当前目录下的 sqlx 脚本文件一键编译为 sql。

如果你使用 Sublime Text 编辑器,可以搜索下载 Sqlx Builder 插件来使用,更加方便。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335