牛客網(wǎng)61道SQL題實(shí)戰(zhàn)總結(jié)

1、前言

結(jié)構(gòu)化查詢語(yǔ)言(Structured Query Language)簡(jiǎn)稱SQL,是一種特殊目的的編程語(yǔ)言,是一種數(shù)據(jù)庫(kù)查詢和程序設(shè)計(jì)語(yǔ)言,用于存取數(shù)據(jù)以及查詢、更新和管理關(guān)系數(shù)據(jù)庫(kù)系統(tǒng);同時(shí)也是數(shù)據(jù)庫(kù)腳本文件的擴(kuò)展名。

差不多花了一周的時(shí)間做完了??途W(wǎng)平臺(tái)的61道SQL題,先說(shuō)一說(shuō)這個(gè)平臺(tái)的坑:

  1. 題目含糊不清,有一些題沒(méi)有準(zhǔn)確表達(dá)意思,會(huì)讓人產(chǎn)生誤解。
  2. OJ的答案判斷比較死板,不是所有正確的解法都能通過(guò)。
  3. 難度不是緩慢遞增,中間有的題會(huì)非常搞人。
  4. 沒(méi)有提供單獨(dú)的測(cè)試數(shù)據(jù),需要去有的題目下面找。
  5. 只支持sqlite,不支持mysql,oracle等其他SQL語(yǔ)言。

再講一講自己的刷題體會(huì):

  1. 比較坑也是一件好事,可以訓(xùn)練思維的全面性,努力去尋找問(wèn)題的不同切入點(diǎn)。
  2. 不要做完了就直接下一題!我個(gè)人最喜歡看評(píng)論,因?yàn)榭梢詫W(xué)習(xí)到前輩們的思路和解法。 首先,我會(huì)在腦海里形成自己的思路,然后和他們的思路進(jìn)行對(duì)比。如果是一致的,哇,我就很開(kāi)心。 如果不一致,則仔細(xì)進(jìn)行比對(duì),找到我的缺陷。
  3. SQL語(yǔ)句不是正確通過(guò)就萬(wàn)事大吉了,盡可能做多一題多解。分析每種解法的優(yōu)化性能,找到 對(duì)應(yīng)的使用場(chǎng)景。
  4. 寫(xiě)法要規(guī)范,注意縮進(jìn),這樣每個(gè)子語(yǔ)句看起來(lái)就比較清晰。
  5. 在動(dòng)手之前先思考一下,不要上來(lái)就急著寫(xiě)。
  6. 了解一些函數(shù),比如窗口函數(shù)等,這些是利器。

如果要二刷,注意以下幾點(diǎn):

  1. 思考題目的真實(shí)使用場(chǎng)景,不要單純做題。
  2. 遇到比較坑的題目,直接跳過(guò),不要多花時(shí)間。
  3. 多歸納總結(jié),必要時(shí)做一下實(shí)驗(yàn)。
  4. 思考一些高階用法,降維打擊。

二刷先放一下,先去刷一下LeetCode的SQL題。那里的題庫(kù)更加正規(guī),還有一些企業(yè)真題。

這么好嗎?畢竟是付費(fèi)的呀 - -。

2、??途W(wǎng)OJ平臺(tái)地址

https://www.nowcoder.com/ta/sql

3、詳細(xì)答題記錄(個(gè)人整理)

https://github.com/HannibalXZX/LearnSQL/tree/master/SQL%E5%AE%9E%E6%88%98-%E7%89%9B%E5%AE%A2%E7%BD%91

4、 筆記

01. left join中on和where的區(qū)別

  1. on條件是在生成臨時(shí)表時(shí)使用的條件,不管on中的條件是否為真,都會(huì)返回左邊表中的記錄。
  2. where條件是在臨時(shí)表生成好后,再對(duì)臨時(shí)表進(jìn)行過(guò)濾的條件。這時(shí)已經(jīng)沒(méi)有l(wèi)eft join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過(guò)濾掉。

02. 三個(gè)連接的簡(jiǎn)單區(qū)別

  • INNER JOIN 兩邊表同時(shí)有對(duì)應(yīng)的數(shù)據(jù),即任何一邊缺失數(shù)據(jù)就不顯示。
  • LEFT JOIN 會(huì)讀取左邊數(shù)據(jù)表的全部數(shù)據(jù),即便右邊表無(wú)對(duì)應(yīng)數(shù)據(jù)。
  • RIGHT JOIN 會(huì)讀取右邊數(shù)據(jù)表的全部數(shù)據(jù),即便左邊表無(wú)對(duì)應(yīng)數(shù)據(jù)

03. 內(nèi)連和并列的區(qū)別

并列,也是等值連接。在這個(gè)過(guò)程中,實(shí)際上是沒(méi)有創(chuàng)建出臨時(shí)的新表,只是為了方便理解,可以認(rèn)為兩張表合并成一張新表,然后再?gòu)脑摫?SELECT所需的字段和記錄。

內(nèi)連可以不等。推薦用內(nèi)連,因?yàn)?,可以將連接條件標(biāo)記得比較清楚。

04. SQL執(zhí)行順序(重要)

FROM、 WHEREGROUP BY、 HAVING、 SELECT、 DISTINCT、 UNION、 ORDER BY

05. GROUP BY 和 DISTINCT

  • 當(dāng)對(duì)系統(tǒng)的性能高并數(shù)據(jù)量大時(shí)使用 GROUP BY
  • 當(dāng)對(duì)系統(tǒng)的性能不高時(shí)使用數(shù)據(jù)量少時(shí)兩者皆可
  • 盡量使用 GROUP BY

針對(duì)網(wǎng)上實(shí)驗(yàn)結(jié)果,還有一種結(jié)論:

去重場(chǎng)景下,未加索引時(shí),更偏向于使用distinct,而加索引時(shí),distinct和group by兩者都可以使用

實(shí)驗(yàn)過(guò)程原文鏈接

06. LEFT JOIN 和 IN

MySQL官方文檔有說(shuō)明, IN關(guān)鍵字適合確定數(shù)量的情況,一般效率較低,不推薦使用。能用 IN關(guān)鍵字的語(yǔ)句都可以轉(zhuǎn)化為使用 JOIN的語(yǔ)句,推薦使用 JOIN關(guān)鍵字。

07. WHERE 和 HAVING

WHEREHAVING的不同之處在于, WHERE是查找之前的限定,而 HAVING是查找之后。如果使用 HAVING,必須提前篩選字段,但 WHERE不需要。 WHERE后面不能加聚合函數(shù), HAVING后可以加聚合函數(shù)。

08. JOIN關(guān)聯(lián)表中ON,WHERE后面跟條件的區(qū)別

不管 ON上的條件是否為真都會(huì)返回 LEFTRIGHT表中的記錄,full則具有 LEFTRIGHT的特性的并集。 而 INNER JOIN沒(méi)這個(gè)特殊性,則條件放在 ON中和 WHERE中,返回的結(jié)果集是相同的。
參考原文鏈接

09. EXPLAIN 函數(shù)作用

  1. 表的讀取順序
  2. 數(shù)據(jù)讀取操作的操作類型
  3. 哪些索引可以使用
  4. 哪些索引被實(shí)際使用
  5. 表之間的引用
  6. 每張表有多少行被優(yōu)化器查詢

10. MySQL創(chuàng)建索引方法:ALTER TABLE和CREATE INDEX的區(qū)別

眾所周知,MySQL創(chuàng)建索引有兩種語(yǔ)法,即:
ALTER TABLEHeadOfStateADD INDEX(LastName,FirstName);
CREATE INDEX index_nameHeadOfState(LastName,FirstName);
那么,這兩種語(yǔ)法有什么區(qū)別呢?

  1. CREATE INDEX必須提供索引名,對(duì)于 ALTER TABLE,如果你不提供索引名,將會(huì)自動(dòng)創(chuàng)建;
  2. CREATE INDEX一個(gè)語(yǔ)句一次只能建立一個(gè)索引, ALTER TABLE可以在一個(gè)語(yǔ)句建立多個(gè),如: ALTER TABLEHeadOfStateADD PRIMARY KEY(ID),ADD INDEX(LastName,FirstName);
  3. 只有 ALTER TABLE才能創(chuàng)建主鍵,

11. 強(qiáng)制索引

MYSQL中強(qiáng)制索引查詢使用: SELECT*FROM table FORCE INDEX(indexname); SQLite中強(qiáng)制索引查詢使用: SELECT*FROM table INDEXED BY indexname;

12. 嚴(yán)格模式

mysql的 datetime類型無(wú)法插入'0000-00-00 00:00:00',這是因?yàn)閙ysql開(kāi)啟了嚴(yán)格模式。

SELECT@@sql_mode 得到如下結(jié)果:

ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

可以看到結(jié)果里面有 NO_ZERO_IN_DATE,NO_ZERO_IN_DATE。把這兩個(gè)去掉,再重新設(shè)置即可。

SET GLOBAL sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

玄學(xué):在Navicat Premium上不行,但在mysql終端上可行

13. MYSQL子查詢的坑

MySQL的 UPDATEDELETE中子查詢不能為同一張表,可將查詢結(jié)果再次 SELECT。在MySQL中還有一個(gè)坑,需要給子查詢添加別名, 不然會(huì)拋出錯(cuò)誤:ERROR 1248 (42000): Every derived table must have its own alias

14. 字符長(zhǎng)度函數(shù)

char_length(): 統(tǒng)計(jì)的是字符長(zhǎng)度,而 LENGTH()函數(shù)統(tǒng)計(jì)的是字符串的字節(jié)長(zhǎng)度,所以 LENGTH('中')在utf8下的結(jié)果是3,而 char_length('中')的結(jié)果仍然是1。

15. EXISTS的用法

EXISTS對(duì)外表用loop逐條查詢,每次查詢都會(huì)查看 EXISTS的條件語(yǔ)句,當(dāng) EXISTS里的條件語(yǔ)句能夠返回記錄行時(shí)(無(wú)論記錄行是的多少),只要能返回,條件就為真。并返回當(dāng)前l(fā)oop到的這條記錄;

反之如果 EXISTS里的條件語(yǔ)句不能返回記錄行,則當(dāng)前l(fā)oop到的這條記錄被丟棄, EXISTS的條件就像一個(gè)bool條件,當(dāng)能返回結(jié)果集則為true,不能返回結(jié)果集則為 false。

簡(jiǎn)而言之,使用 EXISTS需要建立內(nèi)外關(guān)聯(lián)。

  • 沒(méi)有建立內(nèi)外關(guān)聯(lián),等價(jià)于: SELECT b.emp_no FROM employees b
  1. SELECT b.emp_no FROM employees b
  2. WHERE EXISTS (SELECT emp_no FROM dept_emp)
  • 建立內(nèi)外關(guān)聯(lián)
  1. SELECT b.emp_no FROM employees b
  2. WHERE EXISTS (SELECT emp_no FROM dept_emp WHERE b.emp_no=emp_no)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容