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

歡迎訪問 生活随笔!

生活随笔

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

数据库

分享一些常见的SQL计算面试题

發(fā)布時間:2023/12/20 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分享一些常见的SQL计算面试题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

代碼都是基于mysql實現(xiàn),如果小伙伴們有其他的思路歡迎留言~

  • 1.行列轉(zhuǎn)換
  • 2.分組求top-n
  • 3.連續(xù)登錄問題(包括日期可間斷和不可間斷)
  • 4.找連續(xù)出現(xiàn)3次及以上的數(shù)字
  • 4.

1.行列轉(zhuǎn)換

表tb1:

表tb2:

行轉(zhuǎn)列,也就是tb1->tb2,思路是按學(xué)生分組后組內(nèi)分別求各科成績。

selectname as '姓名',max(if(course='語文',score,0)) as '語文', -- 也可以用summax(if(course='數(shù)學(xué)',score,0)) as '數(shù)學(xué)',max(if(course='英語',score,0)) as '英語' from tb1 group by name;

列轉(zhuǎn)行,tb2->tb1,思路是分別選出所有人的各科成績,將各科成績做個union all合并操作。

select姓名 as name,'語文' as course, -- 帶引號表示此處按字符串對待,而不是標(biāo)識符語文 as score from tb2 union all select姓名 as name,'數(shù)學(xué)' as course, 數(shù)學(xué) as score from tb2 union all select姓名 as name,'英語' as course, 英語 as score from tb2;

2.分組求top-n

還用上面行列轉(zhuǎn)換中的那張tb1表,現(xiàn)在求語數(shù)英中各科最高分的學(xué)生

方式1,最簡單的直接使用開窗函數(shù):

select name,course,score from (select*,dense_rank() over(partition by course order by score desc) as rn from tb1 ) tb where tb.rn=1;

結(jié)果:

方式2,下面這種可能沒開窗函數(shù)那么直觀理解,實現(xiàn)思路其實就是從tb1表里面逐條取數(shù)據(jù),每次統(tǒng)計在該記錄所屬課程的所有記錄中,比這個記錄大的所有記錄總數(shù),如果是0,說明這條記錄就是最大的。

select* from tb1where (select count(*) from tb1 tb2 where tb2.course=tb1.course and tb2.score>tb1.score) = 0;

3.連續(xù)登錄問題(包括日期可間斷和不可間斷)

假設(shè)有下面這樣的一張登錄信息表,表名login:

Q1:找出連續(xù)登錄3天及以上的用戶(日期不可間斷)
求解思路是各組內(nèi)對日期排序后在后面標(biāo)記一個連續(xù)遞增值,如果用戶連續(xù)登錄,那登錄日期也應(yīng)該是連續(xù)遞增的,登陸日期減去這個連續(xù)遞增值得到的都是同一個固定值。

selectt.uid,min(t.login_date), -- 連續(xù)登錄的起始日期max(t.login_date), -- 連續(xù)登錄的結(jié)束日期count(*) -- 連續(xù)登天數(shù) from (select*,date_sub(login_date, interval row_number() over(partition by uid order by login_date) day) as sub_datefrom login ) t group by t.uid, -- 這里分組要帶上uid,因為不同用戶登錄日期作差之后結(jié)果可能相等t.sub_date havingcount(*)>=3;

查詢結(jié)果:

Q2:找出連續(xù)登錄3天及以上的用戶(間斷不超過1天也算連續(xù))
例如“2020-01-19”和“2020-01-21”這兩天登錄過,也算連續(xù)3天登錄。

-- 對每組內(nèi)的登陸日期排好序后下移一位,為了避免各組里面下移后的第一個值為null,用'1970-01-01'作為默認(rèn)值 with t1 as (select*,lag(login_date,1,'1970-01-01') over(partition by uid order by login_date) as next_datefrom login ), -- 在上表的基礎(chǔ)上兩日期列作差,如果差值<=2,說明前后兩天連續(xù)或者間斷不超過1天 t2 as (select*,datediff(login_date,next_date) as subfrom t1 ), -- 在上表的基礎(chǔ)上再次使用開窗函數(shù),目的是對組內(nèi)對錄打標(biāo)記,相同值的為連續(xù)登錄組 t3 as (select*,sum(if(sub<=2,0,1)) over(partition by uid order by login_date) as groupidfrom t2 ) -- 最后根據(jù)用戶uid和連續(xù)登錄組進(jìn)行分組,組內(nèi)最大日期-最小日期>=2時滿足連續(xù)3天登錄 selectuid,min(login_date), -- 登錄起始日max(login_date), -- 不滿足連續(xù)時的結(jié)束日datediff(max(login_date),min(login_date))+1 -- 連續(xù)登錄天數(shù) from t3 group by uid,groupid havingdatediff(max(login_date),min(login_date))>=2; -- 注意日期不連續(xù)的時候篩選條件就不能用count(*)了

查詢結(jié)果:

上面的查詢結(jié)果可能會出現(xiàn)同一個用戶出現(xiàn)多次的情況,因為用戶可能會在滿足連續(xù)登錄3天之后間斷一段時間,之后又滿足連續(xù)3天登錄。所以也可以在上面的結(jié)果上基于用戶的uid去個重。

為了方便理解,把上面sql查詢中的t3表結(jié)果貼在下面:

4.找連續(xù)出現(xiàn)3次及以上的數(shù)字

比如說下面這張表,就叫tb表吧,從中選出連續(xù)出現(xiàn)3次及以上的數(shù)字。這是面試中被卡過得一道題,當(dāng)時沒啥好的思路,想通過變量計數(shù)類似代碼編程的方式解決,下來后總覺得不妥,因為畢竟考察的是sql嘛,但又一直想不到好的解法,直到解決了上面那個可間斷日期求連續(xù)的問題,突然發(fā)現(xiàn)這兩題解題思路異曲同工。

下面直接給出代碼,每個中間部分都有解釋:

-- tb表中的num列整體下移一位作為新的一列,第一個值是空值用本身的num填充 with t1 as (select*,lag(num,1,num) over() as next_numfrom tb ), -- 在t1表的基礎(chǔ)上,用num列減去新列值,如果前后兩個數(shù)字連續(xù),則差值為0 t2 as (select*,num-next_num as subfrom t1 ), -- t3主要是用來打標(biāo)記,將相同連續(xù)的數(shù)字后面打上相同的值 -- 思路是在t2表的基礎(chǔ)上從上到下對sub列做累加,如果sub=0,則加上0,否則加上1 t3 as (select*,-- 這里需要顯式指定窗口大小,因為over中沒有進(jìn)行排序操作,默認(rèn)的窗口是整張表sum(if(sub=0,0,1)) over(rows between unbounded preceding and current row) as groupidfrom t2 ) -- 對t3表按照標(biāo)記值groupid分組,組內(nèi)數(shù)據(jù)條數(shù)>=3時滿足至少連續(xù)3次 selectnum, -- 滿足條件的重復(fù)數(shù)字min(id), -- 重復(fù)數(shù)字的起始idmax(id), -- 重復(fù)數(shù)字的結(jié)束idcount(*) -- 重復(fù)次數(shù) from t3 group bygroupid having count(*)>=3;

查詢結(jié)果:

下面將原先那種變量計數(shù)的實現(xiàn)放在下面,可以了解一下:

select distinct num -- 這里需要做個去重,因為根據(jù)過濾條件,一個出現(xiàn)超過3次的數(shù)字會被多次挑選出來 from (select*,case-- @prev保存的是當(dāng)前num的前一個num,如果相等,則計數(shù)+1when @prev=num then @count:=@count+1-- 如果上一步?jīng)]有執(zhí)行走到這一步,說明前后兩個數(shù)字不相等,則將計數(shù)重新置為1,同時將num賦值給@prev變量when (@prev:=num) is not null then @count:=1end as cntfrom tb ) as t where cnt>=3;

這里補充一下mysql中=和:=的區(qū)別,因為開始在這我是有些迷糊的,導(dǎo)致面試中寫的sql沒有跑起來,簡要來說,:=只有賦值的意思,而=包含賦值和比較是否相等兩重意思,具體哪個意思取決于使用場景,所以會有人說當(dāng)使用set @xxx=xxx為變量賦值時二者都可以,當(dāng)使用select @xxx=xxx為變量賦值時必須用:=。
下面附上官方文檔地址和部分截圖:https://dev.mysql.com/doc/refman/8.0/en/assignment-operators.html#operator_assign-equal

4.

總結(jié)

以上是生活随笔為你收集整理的分享一些常见的SQL计算面试题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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