使SQL更易于閱讀的幾個(gè)小技巧
點(diǎn)擊上方“數(shù)據(jù)管道”,選擇“置頂星標(biāo)”公眾號(hào)
干貨福利,第一時(shí)間送達(dá)

無(wú)論是數(shù)倉(cāng)開(kāi)發(fā)還是數(shù)據(jù)分析,寫(xiě)一手好的SQL是一項(xiàng)基本的技能。毋庸置疑,編寫(xiě)性能較好的SQL是非常重要的,但是,SQL的可讀性同樣是不容小覷的。一個(gè)有著混亂格式的SQL腳本,往往需要花費(fèi)較長(zhǎng)的時(shí)間去弄清楚腳本的具體邏輯。如果你曾經(jīng)被祖?zhèn)鞯暮翢o(wú)章法的SQL腳本狂虐過(guò),你一定心有感觸。本文將分享幾個(gè)SQL格式的規(guī)范,當(dāng)然仁者見(jiàn)仁智者見(jiàn)智,其實(shí)沒(méi)有嚴(yán)格的標(biāo)準(zhǔn),如果有,那就是保證易于閱讀和易于維護(hù)。
秦人不暇自哀,而后人哀之;后人哀之而不鑒之,亦使后人而復(fù)哀后人也
大小寫(xiě)保持一致
可以對(duì)SQL關(guān)鍵字使用不同的大小寫(xiě),但是要保持一致??纯催@個(gè):
SELECT?customer_city,count(*)?from?dim_customer?WHERE?customerProvince?=?'上海'?Group?by?customer_city
上面的SQL語(yǔ)句是不是很讓人抓狂,大小寫(xiě)混用,看起來(lái)很不規(guī)范??偨Y(jié)起來(lái),要注意下面幾點(diǎn):
SQL的關(guān)鍵字可以大寫(xiě),也可以小寫(xiě),但是不要大小寫(xiě)混用。上面的SQL查詢既有完全大寫(xiě),也有首字母大寫(xiě),更有小寫(xiě)??此剖遣痪行」?jié),但是萬(wàn)萬(wàn)使不得。 由于大小寫(xiě)是混合的,因此很難區(qū)分小寫(xiě)的關(guān)鍵字實(shí)際上是關(guān)鍵字還是列。此外,閱讀也很煩人。 字段命名要保持一致的風(fēng)格,上面的SQL與中 customer_city是小寫(xiě)加下劃線,而customerProvince字段是駝峰命名法,這種不一致性顯然是不可取的。
進(jìn)行一些規(guī)范之后,查詢應(yīng)如下所示:
SELECT?customer_city,
???????count(*)
FROM?dim_customer
WHERE?customer_province?=?'上海'
GROUP?BY?customer_city
使用縮進(jìn)
再來(lái)看看下面的一條查詢語(yǔ)句:
SELECT?dp.region_name,count(*)?FROM?user_behavior_log?ubl?JOIN?dim_province?dp?ON?ubl.province?=?dp.province_name?WHERE?ubl.province?=?'上海市'?GROUP?BY?dp.region_name
將上面的SQL語(yǔ)句格式化下面的形式:
SELECT?dp.region_name,?count(*)
FROM?user_behavior_log?ubl
JOIN?dim_province?dp?ON?ubl.province?=?dp.province_name
WHERE?ubl.province?=?'上海市'
GROUP?BY?dp.region_name
上面的格式化形式似乎清晰了很多,但是如果語(yǔ)句中包含了子查詢、多個(gè)JOIN以及窗口函數(shù)時(shí),同樣會(huì)顯得對(duì)閱讀不是很友好。
再換一種格式化方式,如下:
SELECT
????dp.region_name,?
????count(*)
FROM?user_behavior_log?ubl
????JOIN?dim_province?dp?ON?ubl.province?=?dp.province_name
WHERE?ubl.province?=?'上海市'
GROUP?BY
????dp.region_name
--?或者下面的形式
SELECT
????dp.region_name?
????,count(*)
FROM?user_behavior_log?ubl
????JOIN?dim_province?dp?ON?ubl.province?=?dp.province_name
WHERE?ubl.province?=?'上海市'
GROUP?BY
????dp.region_name
尖叫提示:對(duì)于第二種形式,在SELECT字段中,從第二個(gè)字段開(kāi)始,每個(gè)字段前面添加一個(gè)逗號(hào),而不是每個(gè)字段后面使用逗號(hào)結(jié)尾。這種方式可以很方便地識(shí)別FROM前面是否存在逗號(hào),從而造成語(yǔ)法錯(cuò)誤。當(dāng)然,這個(gè)只是個(gè)人習(xí)慣問(wèn)題,并不是硬性的規(guī)定。
另外上面的SQL語(yǔ)句使用了4個(gè)字符縮進(jìn),當(dāng)然也可以選擇2個(gè)字符縮進(jìn),這個(gè)也是個(gè)人習(xí)慣問(wèn)題。
在group by 和order by之后使用字段的排列序號(hào)
同樣,這種書(shū)寫(xiě)風(fēng)格也是個(gè)人的一種偏好,并不是一條硬性規(guī)定。應(yīng)該有很多的初學(xué)者對(duì)此種寫(xiě)法并不是很清楚。
看下面的這條SQL:
SELECT
????dp.region_name,?
????dp.province_name,
????count(*)
FROM?user_behavior_log?ubl
????JOIN?dim_province?dp?ON?ubl.province?=?dp.province_name
GROUP?BY
????dp.region_name,
????dp.province_name
ORDER?BY
????count(*)?desc?--?Hive不支持
可以寫(xiě)成下面的形式:
--?注意:MySQL、Impala支持這種寫(xiě)法,Hive不支持
SELECT
????dp.region_name,?
????dp.province_name,
????count(*)
FROM?user_behavior_log?ubl
????JOIN?dim_province?dp?ON?ubl.province?=?dp.province_name
GROUP?BY?1,2
ORDER?BY?3?
這樣寫(xiě)有如下的好處:
可以節(jié)省行:通過(guò)許多字段進(jìn)行分組不僅會(huì)在SELECT子句中添加更多行,還會(huì)在GROUP BY和ORDER BY子句中添加更多行,甚至可能使查詢中的行數(shù)增加一倍。 可維護(hù)性:如果想改變分組字段,只需在SELECT子句中進(jìn)行操作,在GROUP BY語(yǔ)句中不需要修改。 方便:只需要GROUP BY 1,2,3,…,n,其中n為分組列的字段序號(hào)。
使用Common Table表達(dá)式(with語(yǔ)句)
該方式稱之為Common Table Expressions(CTE),用來(lái)簡(jiǎn)化復(fù)雜查詢。它們可以定義為臨時(shí)視圖,因?yàn)樗鼈儍H在整個(gè)查詢執(zhí)行期間存在。
看一個(gè)簡(jiǎn)單的例子:
--?注意Hive、Impala支持這種語(yǔ)法,低版本的MySQL不支持(高版本支持)
WITH?employee_by_title_count?AS?(
????SELECT
????????t.name?as?job_title
????????,?COUNT(e.id)?as?amount_of_employees
????FROM?employees?e
????????JOIN?job_titles?t?on?e.job_title_id?=?t.id
????GROUP?BY?1
),
salaries_by_title?AS?(
?????SELECT
?????????name?as?job_title
?????????,?salary
?????FROM?job_titles
)
SELECT?*
FROM?employee_by_title_count?e
????JOIN?salaries_by_title?s?ON?s.job_title?=?e.job_title
上面的語(yǔ)句中,最終的查詢使用employee_by_title和salaries_by_title的兩個(gè)結(jié)果集進(jìn)行JOIN產(chǎn)生最終結(jié)果。這比在SELECT子句中或直接在FROM子句中進(jìn)行子查詢更具可讀性和可維護(hù)性。
使用具有描述性的別名
這一點(diǎn)非常重要,如果查詢的列字段很多,肯能會(huì)存在一些id,count(*)等,很難辨識(shí)代表什么含義,所以需要為每個(gè)查詢列加上可讀的、易于理解的別名,能夠讓其他人一眼就能看出代表什么含義,這樣可以增加腳本的可維護(hù)性。
總結(jié)
文中提到的一些規(guī)范有些是必須要遵守的,有些是個(gè)人的編碼習(xí)慣,無(wú)論你是開(kāi)發(fā)人員、數(shù)據(jù)分析師、數(shù)倉(cāng)開(kāi)發(fā),遵循一些規(guī)范可以避免不必要的麻煩。值得注意的是,關(guān)于SQL的格式,沒(méi)有一個(gè)標(biāo)準(zhǔn)的約定,需要與團(tuán)隊(duì)的其他成員達(dá)成共識(shí),一起按照相同的約定進(jìn)行開(kāi)發(fā),從而可以大大提高腳本的可讀性和可維護(hù)性。
