今天突然想到了一個需求,即在一張帶有id和time字段的表中,查詢相鄰時間的時間差。
- 表的記錄如下:
表名為wangxin
id是一個不重復的字符串,time是一個時間戳。
- 現在的需求如下:
比如id分別有wangxin1到wangxin4的幾個椅子,小王同學,先坐上wangxin1的椅子,然后坐了幾秒后,又坐到了編號為wangxin2的椅子上,然后一會兒又換到了wangxin3的椅子上,最后坐到wangxin4的椅子上,問,分別在每一個椅子上坐的時間。最后一個默認為0.
- 需求解決思路
想要知道差值,那就意味着必須把時間都比一下,可是只有一張表怎么辦,就只能使用子查詢的方式,利用內連接,獲取到笛卡爾積,即一個時間點對應四個時間點,這樣一來,就方便對其進行一個運算了。
-- 第一步,創建笛卡爾積 SELECT w1.*, w2.* FROM wangxin w1 INNER JOIN (SELECT w3.time FROM wangxin w3) w2 ;
使用內連接的方式創建笛卡爾積,如下所示,這是用來方便計算兩個時間點的差值的:
-- 第二步,進行運算 SELECT w1.id, w1.time,w2.time-w1.time as time_diff FROM wangxin w1 INNER JOIN (SELECT w3.time FROM wangxin w3) w2 ;
這一步運算就是為了計算出兩次的時間差,可見,我們需要的是相近時間點的差值,並且因為是差值,所以只能大於0,故我們第三步整理中,以上一步的結果作為一個新的表,再進行一次select操作,同時我們以time字段分組,並且取time_diff字段非0以外的最小值。
-- 第三步,整理 SELECT t1.id, t1.time, MIN(t1.time_diff) AS time_diff FROM ( SELECT w1.id, w1.time, w2.time - w1.time AS time_diff FROM wangxin w1 INNER JOIN (SELECT w3.time FROM wangxin w3) w2 ) t1 WHERE t1.time_diff > 0 GROUP BY t1.time

這時候,我們發現了咦,為什么wangxin4這個記錄沒有了,原來是因為我們上面采用的是時間差大於0的情況,由於wangxin4后面就沒有新的時間戳了,所以無法計算時間差,故其時間差為0,在上一步的where語句中被略去。
最后我們再加上一不外鏈接
-- 加回原來的表中 SELECT t.*, IFNULL(t2.time_diff, 0) as '時間差' FROM wangxin t LEFT JOIN ( SELECT t1.id, t1.time, MIN(t1.time_diff) AS time_diff FROM ( SELECT w1.id, w1.time, w2.time - w1.time AS time_diff FROM wangxin w1 INNER JOIN (SELECT w3.time FROM wangxin w3) w2 ) t1 WHERE t1.time_diff > 0 GROUP BY t1.time ) t2 ON t.id = t2.id
這一步外鏈接里面需要注意的是,因為上一次的表中沒有id為wangxin4這個記錄,所以在左外鏈接的情況下,就會變成null,因此我們在select語句中,需要對這種情況做一個判斷,判斷是否為null,如果是null的話,就讓這個單元格設置為0
最終結果為:
結果和想象中的一樣。
總結:
之前一直覺得sql很簡單,隨便寫寫就行了,但是今天接觸了一個非常復雜的sql,頓時覺得自己先前真的太幼稚了,sql相對於java更貼近算法,從書寫到優化,發現sql是一門非常厲害的技術,自愧不如、自愧不如哇!
需要學習的東西還很多,與君共勉!