1. 程式人生 > 資料庫 >在工作中常用到的SQL

在工作中常用到的SQL

前言

只有光頭才能變強。
文字已收錄至我的GitHub倉庫,歡迎Star:
最近在公司做了幾張報表,還記得剛開始要做報表的時候都快把SQL給忘光了(當時在廣州休假了1個月多,在實習期間也沒咋寫過SQL),回到公司的第一個需求就是做報表。

於是我很不要臉地跟帶我的學長說:“SQL我好像忘光了,group 分組查詢好像都忘得差不多了,我得複習一下”。

這篇文章來記錄一下我曾經忘掉的group查詢、join查詢等一些比較實用/常用的SQL

  • 本文主打通俗易懂,不涵蓋任何優化(適合新手觀看)

    一、回顧group 查詢

group查詢就是分組查詢,為什麼要分組查詢?因為我們想按某個維度進行統計。下面來看個圖:

在工作中常用到的SQL
現在我的資料如下
比如說,我想知道:每天Java3y這個公眾號的點選量是多少。按我們人工而言,思路很簡單:把相同的天數以及公眾號名稱為Java3y的資料找出來,再將每個點選量相加,就得出了結果了。

在工作中常用到的SQL
步驟
用上SQL我們可能會這樣寫:

select name,time,sum(pv) as pv  
from xxx_table 
where name = 'Java3y' group by name,time

1.1 group 查詢可能存在的誤解

記得有一天,有個群友在群上問了一個問題:
在工作中常用到的SQL
群裡邊的一個問題

其實他的需求很簡單:檢索出資料分組後時間最高的記錄。但他是這樣乾的:

  1. 把先按照時間 order by
  2. 對order by後的記錄進行分組
    示例圖:

在工作中常用到的SQL
群裡面的一個圖

1.2 造成這個誤解的可能原因

有的工具可以支援這種的寫法:

select * from xxx_table group by name

這種寫法沒有被禁止,並可以得出結果,比如得到的結果是:

Java4y    20  7月15號
Java3y    30  7月15號

這種寫法其實是不合理的,要知道的是:使用group by分組統計之後,我們的select 後面只能跟著group by 的欄位,或者是聚合函式。

在工作中常用到的SQL
group by規則
因為,我們對資料進行了分組查詢,資料的分佈情況,我們是不關心的。

記住:先分組,後統計(先把資料歸類後,再對相同的資料進行統計)

1.3 group查詢最常用的SQL

去重是我們經常會遇到的問題,打個比方說,由於各種原因(不管是業務上還是說是髒資料),現在我有兩條重複的資料(除了ID,其餘的欄位都是相同的):

在工作中常用到的SQL
重複的資料
我這邊只希望留下某一條記錄作為查詢結果就好了,我們可以寫下以下的SQL:

select * from user where id in(
   select min(id) from user where name = 'Java3y' and pv = 20 and time='7-25' group by name,pv,time;
)

上面這條SQL是非常非常實用的,除了我說的去重以外,其實我們可以再”思考“一下:

  • 上面已經說了,使用group by分組統計之後,我們的select 後面只能跟著group by 的欄位,或者是聚合函式。
  • 很多時候我們group by了以後,還想要查詢結果中包含group by之外的欄位(一般情況下,我們都不可能將group by 涵蓋所有的欄位),我們就可以上面那樣,將查詢後的結果作為子查詢,放在外部查詢的where 子句後,這樣外部查詢是可以select 出其他欄位的。
    (SQL寫得比較少的朋友可能沒什麼感觸啊,但我希望上面那種寫法大家能夠記住,以後一定會遇到類似的情況的)

二、回顧join查詢

join查詢不知道大家在剛學的時候是怎麼理解的,反正我當初好像就挺迷迷糊糊的。我覺得join查詢可以簡單理解成這樣:我想要的查詢結果,一張表搞不掂,那我就join另一張表

比如說,現在我有兩張的表:

在工作中常用到的SQL
第一張表
在工作中常用到的SQL
第二張表
現在我想知道在7月25號時:每個公眾號的點選量、公眾號名稱、號主名稱、公眾號的建立日期

  • 顯然,我們會發現一張表搞不掂啊,某些資料要依賴於另一張表才能把資料"完整"展示出來
    那join其實就是把兩張表合起來的一個操作:

在工作中常用到的SQL
join其實就是一個合併的操作
兩張表合併起來以後我們就會發現,這張“大表”就含有這兩張表的所有欄位啦,那我想要什麼都有了!

值得注意的是:在join的時候,會產生笛卡爾積(至於什麼是笛卡爾積我這裡就不說了,反正我們要記住的是join表時一定要寫關聯條件去除笛卡爾積)

另外,left join和right join也是我們經常用到,如果我們單純寫join關鍵字,那會被當成是inner join 。下面我簡單解釋一下:

  • 上面說了,在join的時候一定要寫關聯條件,如果是inner join的話,只有符合關聯條件的資料才會存在最大表中
  • 如果是left join的話,即便關聯條件不符合,左邊表的資料一定會存在大表中
  • 如果是right join的話,即便關聯條件不符合,右邊表的資料一定會存在大表中
    看下面的圖:

在工作中常用到的SQL
join
此時我們的兩張表關聯的條件是“公眾號” :如果是inner join,那麼最後我們的表只有兩條記錄。如果是left join ,那麼最後我們的表有三條資料。如果是right join,那麼我們最後的表只有兩條資料

三、回顧case when

SQL中的case when then else end用法其實跟我們程式語言中的if-else很是類似,在寫SQL的時候也常常會用到。

我用得比較多的語法如下:

CASE WHEN sex = '1' THEN '男'
         WHEN sex = '2' THEN '女'
ELSE '其他' END   

在when後面可以跟多個表示式,比如說:

CASE WHEN sex = '1' and name ='Java3y' THEN '男'
         WHEN sex = '2' and name ='Java4y' THEN '女'
ELSE '其他' END   

如果要為case when表示式取別名,在end 關鍵字後邊直接加就好了

更多用法詳情參考:

  • 四、一些常用的函式

4.1 hive和presto解析json

我這邊會有這種情況:將json資料存到MySQL上。我去網上搜了一下以及問了同事,為什麼要將json存到MySQL的欄位上時,他們的答覆都差不多:

  • 在MySQL存json資料,這樣方便擴充套件啊。如果那些欄位不需要用到索引,改動比較頻繁,你又不想改動表的結構,那可以存json。
  • ps:在MySQL 5.7版本以後支援json型別
    參考資料:


  • 我這邊做報表一般來hive或presto上搞的,所以解析json的也是在那上面。

hive解析json函式:

get_json_object(param1,'$.param2')

-- 如果是陣列
get_json_object(xjson,'$.[0].param2')

presto 對json的處理函式:

 -- 陣列  (去除第index個json)
 json_array_get(xjson,index) 

 -- 單個jsoin物件
 json_extract(xjson,'$.param2')

參考資料:

  • 4.2 時間函式

昨天/近7天/本月按照這種指標來查詢也是非常常見的:

昨天

SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ) - TO_DAYS( 時間欄位名) <= 1

7天

SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(時間欄位名)

近30天

SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= date(時間欄位名)

本月

SELECT * FROM 表名 WHERE DATE_FORMAT( 時間欄位名, '%Y%m' ) = DATE_FORMAT( CURDATE( ) , '%Y%m' )

上一月

SELECT * FROM 表名 WHERE PERIOD_DIFF( date_format( now( ) , '%Y%m' ) , date_format( 時間欄位名, '%Y%m' ) ) =1

在presto中使用時間格式,需要明確寫出關鍵字timestamp,比如:

select supplier,count(id) 
from xxx_table 
where sendtime >= timestamp '2019-06-01' 

參考資料:

  • 4.3 其他常用的函式

這裡我簡單整理一下我最近用過函式:

length  --計算字串長度
concat  --連線兩個字串
substring -- 擷取字串
count   -- 統計數量
max   -- 最大
min   -- 最小
sum   -- 合計
floor/ceil  --...數學函式

再來分享一下最近遇到的一個需求,現在有的資料如下:

【Java3y簡單】快樂學習
【Java3y簡單】快樂學習渣渣
【Java3y通俗易懂】簡單學
【Java3y通俗易懂】簡單學芭芭拉
【Java3y平易近人】無聊學
【Java3y初學者】枯燥學
【Java3y初學者】枯燥學呱呱
【Java3y大資料】欣慰學
【Java3y學習】巴拉巴拉學
【Java3y學習】巴拉巴拉學哈哈
【Java3y好】雨女無瓜學

現在我統計出【】括號裡邊出現的頻次,比如說:Java3y通俗易懂出現的頻次是多少。當時一直都沒想到好的思路,都快要搜“SQL 正則表示式 快速入門”了,請教了一下同事,同事很快就寫出來了:

select substring_index(left(title , INSTR(title , '】') -1 ) , '【',-1) 
FROM `xxx_table`

哇~,awesome

推薦閱讀:

  • 工作中常用到的Linux命令
  • 在公司做的專案和自己在學校做的有什麼區別?
  • 目錄|Java3y最全目錄
    在工作中常用到的SQL

200多篇原創技術文章
海量視訊資源
精美腦圖
面試題
長按掃碼可關注獲取