亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

今天就淺顯寫一篇文章專門介紹數據處理中常見的sql查詢場景中的復雜查詢。為什么單獨說復雜查詢呢?因為在業務開發中我們常用orm就可以解決很多查詢問題,但是都是比較簡單的那種sql,所以orm就能滿足。但是一旦涉及到復雜的查詢,orm就束手無策了。這個時候我們一般都是寫sql查詢,但是很多sql還是不太復雜。真正復雜的sql一般都是業務上線之后,領導找你統計各個維度的數據,那么這個時候sql能力就非常重要了,因為它往往涉及很多表很多字段很多子查詢。那為了一天就能掌握寫復雜sql的能力,為此爆肝這篇文章,一起學習成長。

一. 明確需求

返回所有國家以及相關呼叫的數量及其平均持續通話時間(以秒為單位)。在結果中,僅顯示平均呼叫持續時間大于所有呼叫的平均呼叫持續時間的國家。

1. 拆解需求

  1. 需要展示所有國家ID或者國家名稱。
  2. 相關呼叫的數量:展示國家的呼叫統計數量。
  3. 平均持續通話時間:展示國家的呼叫平均持續時間,單位:秒。

2. 條件

僅顯示平均呼叫持續時間大于所有呼叫的平均呼叫持續時間的國家:

那就是先計算所有呼叫的AVG(endTime-startTime),然后每個國家的平均呼叫時間與它比較即可。

3. 涉及到的表:

  1. 國家:country
  2. 呼叫:call
  3. 城市:city
  4. 用戶:customer

為什么需要city和customer表呢?因為call中有外鍵customer,而customer中有外鍵city,city中有外鍵country。

因為要展示所有國家,因此要查詢country,而想統計呼叫,就得鏈接call,怎么能找到call呢,就得從country->city->customer->call。

黑色部分就是需要用到的表

二.開始設計查詢

1. 先寫出整體框架SQL

通過明確需求得知,我們需要關聯四張表:country,city,customer和call。

拆解需求中提到“展示所有國家的名稱”,那么這是大前提,因此如果我們想正確使用這些表,我們需要使用外鍵LEFT JOIN這些表。甚至我們現在不考慮最終查詢,我們就知道它將包含以下部分:

SELECT 
 ...
FROM country 
LEFT JOIN city ON city.country_id = country.id
LEFT JOIN customer ON city.id = customer.city_id
LEFT JOIN call ON call.customer_id = customer.id
...;

到這里我們必須做一件事,那就是測試這樣的查詢返回什么:

SELECT 
 *
FROM country 
LEFT JOIN city ON city.country_id = country.id
LEFT JOIN customer ON city.id = customer.city_id
LEFT JOIN call ON call.customer_id = customer.id;

這一步驟非常必要,因為我們可以看到數據是什么樣子的,為后面的查詢做好基礎。

2. 在添磚加瓦

計算條件中的查詢:

SELECT AVG(DATEDIFF(SECOND, call.start_time, call.end_time)) FROM call

DATEDIFF函數計算開始時間和結束時間之間給定時間段(單位:秒)的單位差。

計算相關呼叫的數量:

SUM(CASE WHEN call.id IS NOT NULL THEN 1 ELSE 0 END) AS calls

SUM函數對呼叫統計數量。

計算平均持續通話時間:

AVG(ISNULL(DATEDIFF(SECOND, call.start_time, call.end_time),0)) AS avg_diff

這里大家可能發現我有對NULL做了判斷,不管是使用ISNULL函數還是IS NOT NULL判斷。為什么呢?因為LEFT JOIN的時候,右邊可能出現NULL的情況,我們怎么知道的呢?這就是我們上面提到的:必須將整體SQL框架先打印看結果,知道數據長啥樣,自然就知道哪里需要用NULL邏輯特殊處理了

好了,現在可以把這些sql添加到SQL框架中了:

SELECT 
 country.country_name,
 SUM(CASE WHEN call.id IS NOT NULL THEN 1 ELSE 0 END) AS calls,
 AVG(ISNULL(DATEDIFF(SECOND, call.start_time, call.end_time),0)) AS avg_diff
FROM country 
LEFT JOIN city ON city.country_id = country.id
LEFT JOIN customer ON city.id = customer.city_id
LEFT JOIN call ON call.customer_id = customer.id
GROUP BY 
 country.id,
 country.country_name

最后一步:按照條件:“僅顯示平均呼叫持續時間大于所有呼叫的平均呼叫持續時間的國家”,我們可以很容易得出,查詢最后的結果需要用HAVING對聚合結果做下過濾,因為“所有呼叫的平均呼叫持續時間”和“均呼叫持續時間”我們已經統計出來了,因此大于長這樣:

HAVING AVG(ISNULL(DATEDIFF(SECOND, call.start_time, call.end_time),0)) > (SELECT AVG(DATEDIFF(SECOND, call.start_time, call.end_time)) FROM call)

所以最后的SQL長這樣:

--返回所有國家以及相關呼叫的數量及其平均持續通話時間(以秒為單位)。在結果中,僅顯示平均呼叫持續時間大于所有呼叫的平均呼叫持續時間的國家。
SELECT 
    country.country_name,
    SUM(CASE WHEN call.id IS NOT NULL THEN 1 ELSE 0 END) AS calls,
    AVG(ISNULL(DATEDIFF(SECOND, call.start_time, call.end_time),0)) AS avg_diff
FROM country 
-- 使用LEFT JOIN包括沒有任何呼叫的國家
LEFT JOIN city ON city.country_id = country.id
LEFT JOIN customer ON city.id = customer.city_id
LEFT JOIN call ON call.customer_id = customer.id
GROUP BY 
    country.id,
    country.country_name
-- 過濾掉不符合條件的結果
HAVING AVG(ISNULL(DATEDIFF(SECOND, call.start_time, call.end_time),0)) > (SELECT AVG(DATEDIFF(SECOND, call.start_time, call.end_time)) FROM call)

三.總結步驟

  1. 先明確需求
  2. 拆解展示字段和條件
  3. 確定所要用到的表
  4. 先寫出整體框架SQL并打印結果看數據很重要這一步
  5. 創建子查詢,并且測試結果,最后添加到整體框架SQL中
  6. 測試驗證所有數據
  7. 添加備注,復雜SQL不寫備注等于沒寫

分享到:
標簽:SQL
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定