成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

四個在工作后才知道的SQL密技

數據庫 SQL Server
SQL是大數據從業者的必備技能,大部分的大數據技術框架也都提供了SQL的解決方案。

[[416328]]

本文會分享四個在面試和工作中常用的幾個使用技巧,具體包括:

  • 日期與期間的高級使用
  • 臨時表與Common Table Expression (WITH)
  • Aggregation 與CASE WHEN的結合使用
  • Window Function的其他用途

數倉?不就是寫寫SQL嗎…

數倉|四個在工作后才知道的SQL密技

日期與時間段的篩選在工作中是經常被用到的,因為在拉取報表、儀表板和各種分析時,周、月、季度、年度的表現往往是分析需要考量的重點。

時間區段的提取:Extract

  • 語法
  1. -- field可以是day、hour、minute, month, quarter等等  
  2. -- source可以是date、timestamp類型  
  3. extract(field FROM source)  
  • 使用
  1. SELECT extract(year FROM '2020-08-05 09:30:08');   -- 結果為 2020  
  2. SELECT extract(quarter FROM '2020-08-05 09:30:08');   -- 結果為 3  
  3. SELECT extract(month FROM '2020-08-05 09:30:08');   -- 結果為 8  
  4. SELECT extract(week FROM '2020-08-05 09:30:08');   -- 結果為 31,一年中的第幾周  
  5. SELECT extract(day FROM '2020-08-05 09:30:08');  -- 結果為 5  
  6. SELECT extract(hour FROM '2020-08-05 09:30:08');   -- 結果為 9  
  7. SELECT extract(minute FROM '2020-08-05 09:30:08');   -- 結果為 30  
  8. SELECT extract(second FROM '2020-08-05 09:30:08');   -- 結果為 8  

注意:

impala支持:YEAR, QUARTER, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, EPOCH

Hive支持:day, dayofweek, hour, minute, month, quarter, second, week 和 year

Hive是從Hive2.2.0版本開始引入該函數

周的提取

  • 語法

在按照周的區間進行統計時,需要識別出周一的日期與周日的日期,這個時候經常會用到下面的函數:

  1. next_day(STRING start_date, STRING day_of_week)  
  2. -- 返回當前日期對應的下一個周幾對應的日期  
  3. -- 2020-08-05為周三  
  4. SELECT next_day('2020-08-05','MO'-- 下一個周一對應的日期:2020-08-10  
  5. SELECT next_day('2020-08-05','TU'-- 下一個周二對應的日期:2020-08-11  
  6. SELECT next_day('2020-08-05','WE'-- 下一個周三對應的日期:2020-08-12  
  7. SELECT next_day('2020-08-05','TH'-- 下一個周四對應的日期:2020-08-06,即為本周四  
  8. SELECT next_day('2020-08-05','FR'-- 下一個周五對應的日期:2020-08-07,即為本周五  
  9. SELECT next_day('2020-08-05','SA'-- 下一個周六對應的日期:2020-08-08,即為本周六  
  10. SELECT next_day('2020-08-05','SU'-- 下一個周日對應的日期:2020-08-09,即為本周日  
  11. -- 星期一到星期日的英文(Monday,Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday)  
  • 使用

那么該如何獲取當前日期所在周的周一對應的日期呢?只需要先獲取當前日期的下周一對應的日期,然后減去7天,即可獲得:

  1. SELECT date_add(next_day('2020-08-05','MO'),-7);  

同理,獲取當前日期所在周的周日對應的日期,只需要先獲取當前日期的下周一對應的日期,然后減去1天,即可獲得:

  1. select date_add(next_day('2020-08-05','MO'),-1)   
  2. -- 2020-08-09  

月的提取

  • 語法

至于怎么將月份從單一日期提取出來呢,LAST_DAY這個函數可以將每個月中的日期變成該月的最后一天(28號,29號,30號或31號),如下:

  1. last_day(STRING date)  
  • 使用
  1. SELECT last_day('2020-08-05'); -- 2020-08-31  

除了上面的方式,也可以使用date_format函數,比如:

  1. SELECT date_format('2020-08-05','yyyy-MM');  
  2. -- 2020-08  

日期的范圍

月的Window:使用add_months加上trunc()的應用

  1. -- 返回加減月份之后對應的日期  
  2. -- 2020-07-05  
  3. select add_months('2020-08-05', -1)  
  4.   
  5. -- 返回當前日期的月初日期  
  6. -- 2020-08-01  
  7. select trunc("2020-08-05",'MM')  

由上面范例可見,單純使用add_months,減N個月的用法,可以剛好取到整數月的數據,但如果加上trunc()函數,則會從前N個月的一號開始取值。

  1. -- 選取2020-07-05到2020-08-05所有數據  
  2. BETWEEN add_months('2020-08-05', -1) AND '2020-08-05'   
  3. -- 選取2020-07-01到2020-08-05之間所有數據  
  4. BETWEEN add_months(trunc("2020-08-05",'MM'),-1) AND '2020-08-05'   
數倉|四個在工作后才知道的SQL密技

這兩種方法是日常工作中經常被使用到,對于一些比較復雜的計算任務,為了避免過多的JOIN,通常會先把一些需要提取的部分數據使用臨時表或是CTE的形式在主要查詢區塊前進行提取。

臨時表的作法:

  1. CREATE TEMPORARY TABLE table_1 AS    
  2.     SELECT   
  3.         columns  
  4.     FROM table A;  
  5. CREATE TEMPORARY table_2 AS   
  6.     SELECT  
  7.         columns  
  8.     FROM table B;  
  9.   
  10. SELECT  
  11.     table_1.columns,  
  12.     table_2.columns,   
  13.     c.columns   
  14. FROM table C JOIN table_1  
  15.      JOIN table_2;  

CTE的作法:

-- 注意Hive、Impala支持這種語法,低版本的MySQL不支持(高版本支持)

  1. -- 注意Hive、Impala支持這種語法,低版本的MySQL不支持(高版本支持)  
  2. WITH employee_by_title_count AS (  
  3.     SELECT  
  4.         t.name as job_title  
  5.         , COUNT(e.id) as amount_of_employees  
  6.     FROM employees e  
  7.         JOIN job_titles t on e.job_title_id = t.id  
  8.     GROUP BY 1  
  9. ),  
  10. salaries_by_title AS (  
  11.      SELECT  
  12.          name as job_title  
  13.          , salary  
  14.      FROM job_titles  
  15. )  
  16. SELECT *  
  17. FROM employee_by_title_count e  
  18.     JOIN salaries_by_title s ON s.job_title = e.job_title  

可以看到TEMP TABLE和CTE WITH的用法其實非常類似,目的都是為了讓你的Query更加一目了然且優雅簡潔。很多人習慣將所有的Query寫在單一的區塊里面,用過多的JOIN或SUBQUERY,導致最后邏輯丟失且自己也搞不清楚寫到哪里,適時的使用TEMP TABLE和CTE作為輔助,絕對是很加分的。

 

數倉|四個在工作后才知道的SQL密技

 

將Aggregation function (SUM/COUNT/COUNT DISTINCT/MIN/MAX) 結合CASE WHEN是最強大且最有趣的使用方式。這樣的使用創造出一種類似EXCEL中SUMIF/COUNTIF的效果,可以用這個方式做出很多高效的分析。

  • Table Name: order
  • Column: register_date, order_date, user_id, country, order_sales, order_id

數據準備

  1. CREATE TABLE order(  
  2.     register_date string,  
  3.     order_date string,  
  4.     user_id string,  
  5.     country string,  
  6.     order_sales decimal(10,2),  
  7.     order_id string);  
  8.   
  9. INSERT INTO TABLE order VALUES("2020-06-07","2020-06-09","001",'c0',210,"o1");  
  10. INSERT INTO TABLE order VALUES("2020-06-08","2020-06-09","002",'c1',220,"o2");  
  11. INSERT INTO TABLE order VALUES("2020-06-07","2020-06-10","003",'c2',230,"o3");  
  12. INSERT INTO TABLE order VALUES("2020-06-09","2020-06-10","004",'c3',200,"o4");  
  13. INSERT INTO TABLE order VALUES("2020-06-07","2020-06-20","005",'c4',300,"o5");  
  14. INSERT INTO TABLE order VALUES("2020-06-10","2020-06-23","006",'c5',400,"o6");  
  15. INSERT INTO TABLE order VALUES("2020-06-07","2020-06-19","007",'c6',600,"o7");  
  16. INSERT INTO TABLE order VALUES("2020-06-12","2020-06-18","008",'c7',700,"o8");  
  17. INSERT INTO TABLE order VALUES("2020-06-07","2020-06-09","009",'c8',100,"o9");  
  18. INSERT INTO TABLE order VALUES("2020-06-15","2020-06-18","0010",'c9',200,"o10");  
  19. INSERT INTO TABLE order VALUES("2020-06-15","2020-06-19","0011",'c10',250,"o11");  
  20. INSERT INTO TABLE order VALUES("2020-06-12","2020-06-29","0012",'c11',270,"o12");  
  21. INSERT INTO TABLE order VALUES("2020-06-16","2020-06-19","0013",'c12',230,"o13");  
  22. INSERT INTO TABLE order VALUES("2020-06-17","2020-06-20","0014",'c13',290,"o14");  
  23. INSERT INTO TABLE order VALUES("2020-06-20","2020-06-29","0015",'c14',203,"o15");  

CASE WHEN 時間,進行留存率/使用率的分析

  1. -- 允許多列去重  
  2. set hive.groupby.skewindata = false  
  3. -- 允許使用位置編號分組或排序  
  4. set hive.groupby.orderby.position.alias = true  
  5.   
  6. SELECT  
  7.     date_add(Next_day(register_date, 'MO'),-1) AS week_end,  
  8.     COUNT(DISTINCT CASE WHEN order_date BETWEEN register_date AND date_add(register_date,6) THEN user_id ENDAS first_week_order,  
  9.     COUNT(DISTINCT CASE WHEN order_date BETWEEN date_add(register_date ,7) AND date_add(register_date,13) THEN user_id ENDAS sencod_week_order,  
  10.     COUNT(DISTINCT CASE WHEN order_date BETWEEN date_add(register_date ,14) AND date_add(register_date,20) THEN user_id ENDas third_week_order  
  11. FROM order  
  12. GROUP BY 1  

上面的示例可以得知到用戶在注冊之后,有沒有創建訂單的行為。比如注冊后的第一周,第二周,第三周分別有多少下單用戶,這樣可以分析出用戶的使用情況和留存情況。

注意:上面的使用方式,需要配置兩個參數:

hive.groupby.skewindata = false:允許多列去重,否則報錯:

SemanticException [Error 10022]: DISTINCT on different columns not supported with skew in data

hive.groupby.orderby.position.alias = true:允許使用位置編號分組或排序,否則報錯:

SemanticException [Error 10025]: line 79:13 Expression not in GROUP BY key ''MO''

CASE WHEN 時間,進行每個用戶消費金額的分析

  1. SELECT  
  2.     user_id,  
  3.     SUM (CASE WHEN order_date BETWEEN register_date AND date_add(register_date,6) THEN order_sales ENDAS first_week_amount,  
  4.     SUM (CASE WHEN order_date BETWEEN date_add(register_date ,7) AND date_add(register_date,13) THEN order_sales ENDAS second_week_amount  
  5.     FROM order  
  6. GROUP BY 1  

通過篩選出注冊與消費的日期,并且進行消費金額統計,每個用戶在每段時間段(注冊后第一周、第二周…以此類推)的消費金額,可以觀察用戶是否有持續維持消費習慣或是消費金額變低等分析。

CASE WHEN數量,消費金額超過某一定額的數量分析

  1. SELECT  
  2.     user_id,  
  3.     COUNT(DISTINCT CASE WHEN order_sales >= 100 THEN order_id ENDAS count_of_order_greateer_than_100  
  4. FROM order  
  5. GROUP BY 1  

上面的示例就是類似countif的用法,針對每個用戶,統計其訂單金額大于某個值的訂單數量,分析去篩選出高價值的顧客。

CASE WHEN數量,加上時間的用法

  1. SELECT  
  2.     user_id,  
  3.     MIN(CASE WHEN order_sales > 100 THEN order_date ENDAS first_order_date_over1000,  
  4.     MAX(CASE WHEN order_sales > 100 THEN order_date ENDAS recent_order_date_over100  
  5. FROM order  
  6. GROUP BY 1  

CASE WHEN加上MIN/MAX時間,可以得出該用戶在其整個使用過程中,首次購買超過一定金額的訂單日期,以及最近一次購買超過一定金額的訂單日期。

數倉|四個在工作后才知道的SQL密技

Window Function既是工作中經常使用的函數,也是面試時經常被問到的問題。常見的使用場景是分組取topN。本文介紹的另外一個用法,使用開窗函數進行用戶訪問session分析。

session是指在指定的時間段內用戶在網站上發生的一系列互動。例如,一次session可以包含多個網頁瀏覽、事件、社交互動和電子商務交易。session就相當于一個容器,其中包含了用戶在網站上執行的操作。

數倉|四個在工作后才知道的SQL密技

session具有一個過期時間,比如30分鐘,即不活動狀態超過 30 分鐘,該session就會過時。

假設張三訪問了網站,從他到達網站的那一刻開始,就開始計時。如果過了 30 分鐘,而張三仍然沒有進行任何形式的互動,則視為本次session結束。但是,只要張三與某個元素進行了互動(例如發生了某個事件、社交互動或打開了新網頁),就會在該次互動的時間基礎上再增加 30 分鐘,從而重置過期時間。

數倉|四個在工作后才知道的SQL密技

數據準備

  • Table Name: user_visit_action
  • Columns: user_id, session_id , page_url, action_time
  1. CREATE TABLE user_visit_action(   
  2.     user_id string,  
  3.     session_id string,  
  4.     page_url string,  
  5.     action_time string);  
  6.       
  7. INSERT INTO TABLE user_visit_action VALUES("001","ss001","http://a.com","2020-08-06 13:34:11.478");  
  8. INSERT INTO TABLE user_visit_action VALUES("001","ss001","http://b.com","2020-08-06 13:35:11.478");  
  9. INSERT INTO TABLE user_visit_action VALUES("001","ss001","http://c.com","2020-08-06 13:36:11.478");  
  10.   
  11. INSERT INTO TABLE user_visit_action VALUES("001","ss002","http://a.com","2020-08-06 14:30:11.478");  
  12. INSERT INTO TABLE user_visit_action VALUES("001","ss002","http://b.com","2020-08-06 14:31:11.478");  
  13. INSERT INTO TABLE user_visit_action VALUES("001","ss002","http://e.com","2020-08-06 14:33:11.478");  
  14. INSERT INTO TABLE user_visit_action VALUES("001","ss002","http://f.com","2020-08-06 14:35:11.478");  
  15.   
  16. INSERT INTO TABLE user_visit_action VALUES("002","ss003","http://u.com","2020-08-06 18:34:11.478");  
  17. INSERT INTO TABLE user_visit_action VALUES("002","ss003","http://k.com","2020-08-06 18:38:11.478");  

用戶訪問session分析

范例的資料表如上,有使用者、訪次和頁面的連接和時間。以下則使用partition by來表達每個使用者在不同訪次之間的瀏覽行為。

  1. SELECT  
  2.     user_id,  
  3.     session_id,  
  4.     page_url,  
  5.     DENSE_RANK() OVER (PARTITION BY user_id, session_id ORDER BY action_time ASCAS page_order,  
  6.     MIN(action_time) OVER (PARTITION BY user_id, session_id) AS session_start_time,  
  7.     MAX(action_time) OVER (PARTITION BY user_id, session_id) AS session_finisht_time  
  8. FROM user_visit_action  

上面的查詢會返回針對每個用戶、每次的到訪,瀏覽頁面行為的先后次序,以及該session開始與結束的時間,以此為基礎就可以將這個結果存入TEMP TABLE或是CTE ,進行更進一步的分析。

小結

本文主要分享了四個在工作和面試中經常遇到的SQL使用技巧。當然,這些都與具體的分析業務息息相關。最后,不管你是SQL boy or SQL girl,只要是掌握一些技巧,相信都能夠Happy SQL querying 。

 

責任編輯:華軒 來源: 今日頭條
相關推薦

2022-06-30 08:31:54

排序函數SQL

2023-04-11 08:49:42

排序函數SQL

2021-08-10 08:01:08

Synchronize鎖膨脹鎖消除

2023-11-03 00:28:44

ApacheFlink

2024-11-04 14:18:32

JavaScript編程語言開發

2023-07-06 07:09:03

云原生工具架構

2024-01-18 07:46:53

HookReact回調函數

2015-03-30 12:54:55

SQL ServerSQL Server

2022-07-01 13:56:41

云計算混合云遷移云

2016-12-09 09:31:22

HadoopSQL大數據

2013-03-18 13:31:28

2024-06-25 12:45:05

2015-06-10 16:23:33

WWDC庫克蘋果

2022-02-23 15:09:18

數字化轉型國有企業數據

2011-03-21 10:26:10

SQL Server視圖管理

2011-03-28 17:12:36

SQL Server數轉換服務

2023-05-24 06:56:18

實用AI工具

2025-02-27 08:33:13

2020-06-04 08:15:53

Kubernetes容器PaaS
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 超碰日韩 | 欧美精品福利视频 | 亚洲第一视频网站 | 九九精品在线 | 久久国产精品72免费观看 | 亚洲精品久久久久久首妖 | 精品中文在线 | 一区二区三区中文字幕 | 自拍偷拍第一页 | 日韩在线国产 | 夜夜爽99久久国产综合精品女不卡 | 日干夜干| 久久久久久黄 | 午夜手机在线视频 | 欧美mv日韩mv国产网站91进入 | 香蕉91| 亚洲综合久久久 | 中文字幕1区2区 | 国精产品一品二品国精在线观看 | 秋霞国产 | 亚洲视频免费在线观看 | 草草视频在线观看 | 国产高清久久 | 一区二区三区免费 | 97精品国产97久久久久久免费 | 色综合久| 日本精品一区二区 | 日本aⅴ中文字幕 | 91高清视频在线观看 | 国产精品国产精品国产专区不卡 | 国产视频一区二区三区四区五区 | 日韩欧美在线一区 | 久久99蜜桃综合影院免费观看 | 国产婷婷精品av在线 | 在线国产一区二区 | 中文字幕亚洲专区 | 一区二区三区四区免费在线观看 | 欧美成年网站 | 成人av一区 | 狠狠狠| 日本精品久久久一区二区三区 |