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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

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

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

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

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

1.行列轉換

表tb1:

表tb2:

行轉列,也就是tb1->tb2,思路是按學生分組后組內分別求各科成績。

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

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

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

2.分組求top-n

還用上面行列轉換中的那張tb1表,現在求語數英中各科最高分的學生

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

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;

結果:

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

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

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

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

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

selectt.uid,min(t.login_date), -- 連續登錄的起始日期max(t.login_date), -- 連續登錄的結束日期count(*) -- 連續登天數 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,因為不同用戶登錄日期作差之后結果可能相等t.sub_date havingcount(*)>=3;

查詢結果:

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

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

查詢結果:

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

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

4.找連續出現3次及以上的數字

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

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

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

查詢結果:

下面將原先那種變量計數的實現放在下面,可以了解一下:

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

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

4.

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。