日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

拼多多大数据开发工程师SQL实战解析

發(fā)布時(shí)間:2024/3/24 数据库 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 拼多多大数据开发工程师SQL实战解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

不久前,裸考國(guó)內(nèi)知名電商平臺(tái)拼多多的大數(shù)據(jù)崗位在線筆試,問(wèn)答題(寫(xiě)SQL)被虐的很慘,完了下來(lái)默默學(xué)習(xí)一波。順便借此機(jī)會(huì)復(fù)習(xí)一下SQL語(yǔ)句的用法。

本文主要涉及到的SQL知識(shí)點(diǎn)包括CREATE創(chuàng)建數(shù)據(jù)庫(kù)和表、INSERT插入數(shù)據(jù)、SUM()求和、GROUP BY分組、DATE_FORMAT()格式化日期、ORDER BY排序、COUNT()統(tǒng)計(jì)行數(shù)、添加排名、MySQL實(shí)現(xiàn)統(tǒng)計(jì)排名、并列排名等,如果你對(duì)這些操作還有點(diǎn)不熟練,那么相信你讀完本文會(huì)有收獲的,如果自己再實(shí)現(xiàn)一遍效果更好。

準(zhǔn)備工作

根據(jù)筆試時(shí)遺留的線索,在本地MySQL創(chuàng)建數(shù)據(jù)庫(kù)和表,為后續(xù)鋪墊。

  • 創(chuàng)建數(shù)據(jù)庫(kù)和表

CREATE DATABASE語(yǔ)句用于創(chuàng)建數(shù)據(jù)庫(kù),基本語(yǔ)法如下:

CREATE DATABASE database_name

在本地創(chuàng)建一個(gè)名為test的測(cè)試數(shù)據(jù)庫(kù):

CREATE TABLE test;

CREATE TABLE語(yǔ)句用于創(chuàng)建表,基本語(yǔ)法如下:

CREATE TABLE table_name(column_name1 type,column_name2 type,column_name3 type,... )

在test數(shù)據(jù)庫(kù)下面創(chuàng)建一張名為orders的表:

USE test; CREATE TABLE orders(id INT PRIMARY KEY AUTO_INCREMENT,order_time TIMESTAMP,cate VARCHAR(255),goods_id int,order_amount int )
  • 插入數(shù)據(jù)

INSERT INTO 語(yǔ)句用于向表格中插入新的行,基本語(yǔ)法如下:

INSERT INTO table_name VALUES (value1, value2,....)

向orders表中插入一些測(cè)試數(shù)據(jù):

INSERT INTO orders(order_time,cate,goods_id,order_amount) VALUES ('2018-02-28 00:00:01', '水果',223,100), ('2018-02-28 01:01:01', '花茶',444,111), ('2018-02-28 06:06:06', '花茶',444,666), ('2018-03-01 07:01:10', '花茶',5555,170), ('2018-03-01 08:00:00', '花茶',5555,180), ('2018-03-01 00:00:01', '花茶',333,100), ('2018-03-01 00:00:01', '花茶',444,188), ('2018-03-01 00:00:01', '數(shù)碼',45454,5399)

結(jié)果如圖所示:

題目解析

  • 請(qǐng)統(tǒng)計(jì)2018年全年每月銷售金額,按下表格式返回。

  • 日期銷售金額
    2018-01****
    2018-02****
    ......

    分析:統(tǒng)計(jì)每月的銷售金額,需要用到求和函數(shù)SUM()。SUM()函數(shù)用于返回?cái)?shù)值列的總和。基本語(yǔ)法如下:

    SELECT SUM(column_name) FROM table_name

    求和通常需要用到GROUP BY,GROUP BY可以根據(jù)一個(gè)或多個(gè)列對(duì)結(jié)果集進(jìn)行分組,本題也是這個(gè)套路,需要根據(jù)月份進(jìn)行分組統(tǒng)計(jì)。GROUP BY的基本語(yǔ)法如下:

    SELECT column_name, aggregate_function(column_name) FROM table_name WHERE column_name operator value GROUP BY column_name

    當(dāng)然本題還有其他附加要求,按照規(guī)定形式返回,需要對(duì)日期進(jìn)行進(jìn)行格式化處理。DATE_FORMAT() 函數(shù)用于以不同的格式顯示日期/時(shí)間數(shù)據(jù),基本語(yǔ)法如下:

    DATE_FORMAT(date,format)

    date 參數(shù)是合法的日期。format 規(guī)定日期/時(shí)間的輸出格式。可以使用的格式有:

    格式描述
    %a縮寫(xiě)星期名
    %b縮寫(xiě)月名
    %c月,數(shù)值
    %D帶有英文前綴的月中的天
    %d月的天,數(shù)值(00-31)
    %e月的天,數(shù)值(0-31)
    %f微秒
    %H小時(shí) (00-23)
    %h小時(shí) (01-12)
    %I小時(shí) (01-12)
    %i分鐘,數(shù)值(00-59)
    %j年的天 (001-366)
    %k小時(shí) (0-23)
    %l小時(shí) (1-12)
    %M月名
    %m月,數(shù)值(00-12)
    %pAM 或 PM
    %r時(shí)間,12-小時(shí)(hh:mm:ss AM 或 PM)
    %S秒(00-59)
    %s秒(00-59)
    %T時(shí)間, 24-小時(shí) (hh:mm:ss)
    %U周 (00-53) 星期日是一周的第一天
    %u周 (00-53) 星期一是一周的第一天
    %V周 (01-53) 星期日是一周的第一天,與 %X 使用
    %v周 (01-53) 星期一是一周的第一天,與 %x 使用
    %W星期名
    %w周的天 (0=星期日, 6=星期六)
    %X年,其中的星期日是周的第一天,4 位,與 %V 使用
    %x年,其中的星期一是周的第一天,4 位,與 %v 使用
    %Y年,4 位
    %y年,2 位

    本題中的形式可以用DATE_FORMAT(t.order_time,'%Y-%m')把時(shí)間格式化成表格中的形式(年份-月份),然后按照題目要求的別名返回即可。

    這題比較簡(jiǎn)單,分析了這么多,可以直接寫(xiě)SQL語(yǔ)句了:

    SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS '日期', SUM(t.order_amount) AS '銷售金額' FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time)

    執(zhí)行結(jié)果正確,如圖:

  • 請(qǐng)統(tǒng)計(jì)2018年每月銷售金額,以及金額排名。

  • 日期銷售金額金額排名
    2018-01****2
    2018-02****3
    .........
    2018-12****9

    這個(gè)題是要求銷售金額的排名情況,求這個(gè)月的銷售額在這一年的12月中排第幾,需要得到具體排第幾名。比如說(shuō)2018年1月的銷售金額在12個(gè)月中排第2名。不是用ORDER BY粗暴的進(jìn)行排序完事!不是用ORDER BY粗暴的進(jìn)行排序完事!不是用ORDER BY粗暴的進(jìn)行排序完事!這個(gè)是我理解的題意。

    對(duì)于這個(gè)問(wèn)題,我剛開(kāi)始也是比較懵逼的,沒(méi)有思路。感覺(jué)這道題還有點(diǎn)東西哈。網(wǎng)上搜索了一下,沒(méi)有找到和我這個(gè)需求一模一樣的,看了一些相似的博客,然后從這些博客中找到了解答本題的思路。

    在這過(guò)程中我也嘗試著在某個(gè)技術(shù)交流群里面請(qǐng)教了一下各位技術(shù)大佬,有說(shuō)用ORDER BY就好了的,有說(shuō)用LIMIT的,還有的說(shuō)問(wèn)這么傻的問(wèn)題。。。如果一個(gè)ORDER BY就可以輕易解答這個(gè)問(wèn)題,我特么用得著來(lái)群里問(wèn)你們?只好留下一句”我們的ORDER BY好像不是太一樣,打擾了“,然后默默離開(kāi),沒(méi)有失望,也沒(méi)有憤怒。

    因?yàn)槲叶嗄昵霸缫步?jīng)習(xí)慣了,習(xí)慣了大多數(shù)時(shí)候在群里面請(qǐng)教問(wèn)題,不僅得不到滿意的解答,反而會(huì)遭到各種冷嘲熱諷。我也常常在反思這個(gè)問(wèn)題,別人的問(wèn)題難倒真的沒(méi)有一絲價(jià)值嗎?難倒我們真的是別人口中所說(shuō)的“技術(shù)大佬”,別人的難題對(duì)于自己來(lái)說(shuō)都不算是問(wèn)題嗎?有些時(shí)候,看到一些交流群里的問(wèn)題,貌似很簡(jiǎn)單,但是有時(shí)候做起來(lái)還真的不好做;就像面試的時(shí)候手撕個(gè)很簡(jiǎn)單的算法(比如快速排序、堆排序),很難保證“一次編寫(xiě),到處正確運(yùn)行”。所以,面對(duì)別人的問(wèn)題,我都告訴自己要認(rèn)真對(duì)待。因?yàn)榇蠖鄶?shù)人是在自己解決不了的時(shí)候才會(huì)把問(wèn)題拋出來(lái),沒(méi)有誰(shuí)天生喜歡厚著臉皮去求人解答,這往往是更有價(jià)值的問(wèn)題,是有助于提高自己的問(wèn)題。哎,好像扯得有點(diǎn)遠(yuǎn)了。下面繼續(xù)說(shuō)這個(gè)問(wèn)題。

    看了看網(wǎng)上相似的問(wèn)題,結(jié)合自己的分析,我覺(jué)得這道題完全可以解答出來(lái),即使我使用的是MySQL數(shù)據(jù)庫(kù)(MySQL數(shù)據(jù)庫(kù)不能使用rank()函數(shù))。這個(gè)問(wèn)題可以分三個(gè)步驟解決:

  • 在第(1)問(wèn)的基礎(chǔ)上按照銷售金額進(jìn)行排序;要求排名,當(dāng)然先要按銷售金額排序。
  • ORDER BY 用于對(duì)結(jié)果集按照一個(gè)列或者多個(gè)列進(jìn)行排序。基本語(yǔ)法如下:

    SELECT column_name,column_name FROM table_name ORDER BY column_name,column_name ASC|DESC;

    對(duì)金額進(jìn)行排序(降序需要加上DESC關(guān)鍵字):

    SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC

    為了排序和之后的效果顯示,我又在表格中插入了2018年4月的記錄。排序之后的結(jié)果如圖所示:

  • 對(duì)排序的結(jié)果添加一個(gè)排名列;其實(shí)就是在上圖結(jié)果后面添加一個(gè)排名字段。這里自定義一個(gè)排名變量rank,初始化為0,由于數(shù)據(jù)已經(jīng)是排好序的,所以每次加1就是排名,從而實(shí)現(xiàn)一個(gè)取得排序后名次的效果。
  • 在MySQL中聲明一個(gè)變量,需要在變量名之前使用@符號(hào)。FROM子句中的(@rank:= 0)部分可以進(jìn)行變量初始化,而不需要單獨(dú)的SET命令。更多關(guān)于MySQL自定義變量可以參考Mysql自定義變量的使用和MySQL官網(wǎng)文檔用戶自定義變量。

    例子:

    SELECT (@rank := @rank+1) AS rank FROM ( SELECT * FROM table_name ) a,(SELECT @rank :=0) b

    對(duì)本題中的銷售金額進(jìn)行排序后添加排名列的SQL語(yǔ)句:

    SELECT a.mon AS r,a.sum AS x,@rank :=@rank + 1 AS j FROM (SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC) a,(SELECT @rank := 0) b

    執(zhí)行結(jié)果如圖:

    這樣就實(shí)現(xiàn)了簡(jiǎn)單的rank排名函數(shù),也基本滿足了題意。但是這樣寫(xiě)還有一個(gè)問(wèn)題需要注意,遇到銷售金額相等的情況,名次也會(huì)加1。如果向表中再插入一條記錄2018年5月的記錄,使得5月份的銷售金額和2月份相等:INSERT INTO orders(order_time,cate,goods_id,order_amount) VALUES ('2018-05-22 13:23:39', '果粒橙',111,877),再去執(zhí)行剛才的查詢操作,結(jié)果如圖:

    可以看見(jiàn)圖中2018年2月和2018年5月的銷售額都是877,2月排第2,5月排第3。這樣排名貌似不合理吧?

    還有更神奇的呢!再次執(zhí)行相同的操作,結(jié)果卻不相同。what?這次5月排第2,2月排第3了?什么情況?關(guān)于ORDER BY排序以后順序?yàn)槭裁措S機(jī),我需要再好好研究一下MySQL底層原理。所以這個(gè)問(wèn)題先留著。

    如果是面試的話,在上面排名情況這個(gè)細(xì)節(jié)問(wèn)題上就需要和面試官進(jìn)行交流了,銷售金額會(huì)不會(huì)有相等的情況?如果有相等的情況,遇到名次并列情況怎么辦?如果說(shuō)第1名有1個(gè),第2名有兩個(gè)并列,那么接下來(lái)的排名是第3名還是第4名呢?

    接下來(lái)實(shí)現(xiàn)并列排名。如果題目要求相同數(shù)據(jù)并列排名,求排名的時(shí)候,需要拿前一個(gè)排名的數(shù)據(jù)來(lái)對(duì)比從而判斷排名是否進(jìn)行加1操作。SQL層面則需要自定義兩個(gè)變量,一個(gè)記錄之前排名的數(shù)據(jù),一個(gè)記錄現(xiàn)在的排名。如果之前排名的數(shù)據(jù)等于需要排名的數(shù)據(jù),那么就是并列,排名不變。如果不相等,排名加1。也許我描述的不夠清楚,看看SQL語(yǔ)句估計(jì)就明白了:

    SELECT a.mon AS r,a.sum AS x, CASE WHEN @prevRank = a.sum THEN @curRank WHEN @prevRank := a.sum THEN @curRank := @curRank + 1 END AS j FROM (SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC) a,(SELECT @curRank :=0, @prevRank := NULL) b

    執(zhí)行上述語(yǔ)句,2月和5月排名實(shí)現(xiàn)了并列,如圖:

    上面實(shí)現(xiàn)了普通并列排名,如果想實(shí)現(xiàn)高級(jí)并列排名(使上圖中2018年4月數(shù)據(jù)排第4),需要定義3個(gè)變量,寫(xiě)起來(lái)有點(diǎn)復(fù)雜,這里先不寫(xiě)了。關(guān)于高級(jí)并列排名可以參考:在MySQL中實(shí)現(xiàn)Rank高級(jí)排名函數(shù)。

  • 在第二步的基礎(chǔ)上按照月份排序,完成。
  • 經(jīng)過(guò)了上面的步驟,離目標(biāo)僅有一步之遙:按月份排序,還有替換別名。第二步的結(jié)果當(dāng)成一張表,新建一個(gè)查詢,對(duì)其進(jìn)行月份排列,并把列名替換成為最終題目需要的列名即可。

    SELECT tt.r AS '日期',tt.x AS '銷售金額',tt.j AS '金額排名' FROM (SELECT a.mon AS r,a.sum AS x, CASE WHEN @prevRank = a.sum THEN @curRank WHEN @prevRank := a.sum THEN @curRank := @curRank + 1 END AS j FROM (SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC) a,(SELECT @curRank :=0, @prevRank := NULL) b) tt ORDER BY tt.r

    結(jié)果如我所愿:

  • 請(qǐng)用SQL選出2018年2月每個(gè)類目銷量最高的2個(gè)爆款商品以及排名先后。

  • 類目商品id排名
    水果2231
    花茶4441
    花茶55552
    數(shù)碼454541

    這個(gè)問(wèn)題是考察分組排名的問(wèn)題:按照商品類目進(jìn)行分組,按goods_id統(tǒng)計(jì)行數(shù)作為銷量,找出每個(gè)商品種類銷量前2名的goods_id,并給出排名。如果已經(jīng)完全理解了第2問(wèn)的使用自定義變量來(lái)實(shí)現(xiàn)添加排名操作,這一問(wèn)做起來(lái)會(huì)輕松許多。

    銷量怎么計(jì)算?題目中沒(méi)有明確說(shuō)明,我理解的銷量應(yīng)該是表中的記錄行數(shù)。統(tǒng)計(jì)記錄行數(shù)需要使用COUNT()函數(shù),基本語(yǔ)法如下:

    SELECT COUNT(column_name) FROM table_name

    這個(gè)問(wèn)題也可以分三個(gè)步驟解決:

  • 統(tǒng)計(jì)出來(lái)每種商品的銷量,并按照類目、銷量進(jìn)行排序;這里由于表中的數(shù)據(jù)庫(kù)記錄較少,所以我直接統(tǒng)計(jì)的是2018年全年的數(shù)據(jù),其實(shí)道理是一樣的。SQL語(yǔ)句如下:
  • SELECTa.cate,a.goods_id,a.count FROM (SELECT t.cate,t.goods_id,count(goods_id) AS countFROM orders tWHERE date_format(t.order_time, '%Y%m%d%H%i%s')LIKE "2018%"GROUP BY t.goods_idORDER BY t.cate,count(t.goods_id) DESC ) AS a

    執(zhí)行結(jié)果如圖:

  • 使用自定義變量為排序結(jié)果添加排名。原理和用法與上一個(gè)問(wèn)題是一樣的,這里不贅述了。SQL語(yǔ)句如下:
  • SELECTa.cate,a.goods_id,a.count,@rank:= CASE WHEN @prevCate=a.cate THEN @rank+1 ELSE 1 END AS rankNO,@prevCate:=a.cate AS type FROM (SELECT t.cate,t.goods_id,count(goods_id) AS countFROM orders tWHERE date_format(t.order_time, '%Y%m%d%H%i%s')LIKE "2018%"GROUP BY t.goods_idORDER BY t.cate,count(t.goods_id) DESC ) AS a,(SELECT @rank:=0 ,@prevCate:='') b

    執(zhí)行結(jié)果如圖:

  • 根據(jù)rankNO篩選前2名并按照題目要求格式返回;由于前面的鋪墊,只需要用WHERE對(duì)rankNO進(jìn)行篩選。SQL語(yǔ)句如下:
  • SELECT t.cate AS '類目',t.goods_id AS '商品id',t.rankNO AS '排名' FROM (SELECTa.cate,a.goods_id,a.count,@rank:= CASE WHEN @prevCate=a.cate THEN @rank+1 ELSE 1 END AS rankNO,@prevCate:=a.cate AS type FROM (SELECT t.cate,t.goods_id,count(goods_id) AS countFROM orders tWHERE date_format(t.order_time, '%Y%m%d%H%i%s')LIKE "2018%"GROUP BY t.goods_idORDER BY t.cate,count(t.goods_id) DESC ) AS a,(SELECT @rank:=0 ,@prevCate:='') b) t WHERE t.rankNO <= 2

    執(zhí)行結(jié)果和要求一模一樣:

    總結(jié)

    筆試已涼,但是學(xué)習(xí)之路沒(méi)有終點(diǎn)。經(jīng)過(guò)幾天的學(xué)習(xí)和調(diào)試,終于解決了這個(gè)SQL語(yǔ)句的問(wèn)題,也算是了卻了一樁心事。

    本文僅根據(jù)題目要求實(shí)現(xiàn)了基本功能,關(guān)于性能方面的問(wèn)題還沒(méi)有考慮。在大數(shù)據(jù)量的情況下這么寫(xiě)是否還可以接受呢?應(yīng)該怎么優(yōu)化?ORDEY BY排序以后相同數(shù)據(jù)順序隨機(jī)究竟和底層索引之間有怎么的聯(lián)系?由于水平有限,這些問(wèn)題我還需要再好好研究一番,也希望各位可以多指教。

    轉(zhuǎn)載于:https://www.cnblogs.com/sgh1023/p/10591849.html

    總結(jié)

    以上是生活随笔為你收集整理的拼多多大数据开发工程师SQL实战解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。