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)的坑:
- 題目含糊不清,有一些題沒(méi)有準(zhǔn)確表達(dá)意思,會(huì)讓人產(chǎn)生誤解。
- OJ的答案判斷比較死板,不是所有正確的解法都能通過(guò)。
- 難度不是緩慢遞增,中間有的題會(huì)非常搞人。
- 沒(méi)有提供單獨(dú)的測(cè)試數(shù)據(jù),需要去有的題目下面找。
- 只支持sqlite,不支持mysql,oracle等其他SQL語(yǔ)言。
再講一講自己的刷題體會(huì):
- 比較坑也是一件好事,可以訓(xùn)練思維的全面性,努力去尋找問(wèn)題的不同切入點(diǎn)。
- 不要做完了就直接下一題!我個(gè)人最喜歡看評(píng)論,因?yàn)榭梢詫W(xué)習(xí)到前輩們的思路和解法。 首先,我會(huì)在腦海里形成自己的思路,然后和他們的思路進(jìn)行對(duì)比。如果是一致的,哇,我就很開(kāi)心。 如果不一致,則仔細(xì)進(jìn)行比對(duì),找到我的缺陷。
- SQL語(yǔ)句不是正確通過(guò)就萬(wàn)事大吉了,盡可能做多一題多解。分析每種解法的優(yōu)化性能,找到 對(duì)應(yīng)的使用場(chǎng)景。
- 寫(xiě)法要規(guī)范,注意縮進(jìn),這樣每個(gè)子語(yǔ)句看起來(lái)就比較清晰。
- 在動(dòng)手之前先思考一下,不要上來(lái)就急著寫(xiě)。
- 了解一些函數(shù),比如窗口函數(shù)等,這些是利器。
如果要二刷,注意以下幾點(diǎn):
- 思考題目的真實(shí)使用場(chǎng)景,不要單純做題。
- 遇到比較坑的題目,直接跳過(guò),不要多花時(shí)間。
- 多歸納總結(jié),必要時(shí)做一下實(shí)驗(yàn)。
- 思考一些高階用法,降維打擊。
二刷先放一下,先去刷一下LeetCode的SQL題。那里的題庫(kù)更加正規(guī),還有一些企業(yè)真題。
這么好嗎?畢竟是付費(fèi)的呀 - -。
2、??途W(wǎng)OJ平臺(tái)地址
https://www.nowcoder.com/ta/sql
3、詳細(xì)答題記錄(個(gè)人整理)
4、 筆記
01. left join中on和where的區(qū)別
-
on條件是在生成臨時(shí)表時(shí)使用的條件,不管on中的條件是否為真,都會(huì)返回左邊表中的記錄。 -
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、 WHERE、 GROUP 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兩者都可以使用
06. LEFT JOIN 和 IN
MySQL官方文檔有說(shuō)明, IN關(guān)鍵字適合確定數(shù)量的情況,一般效率較低,不推薦使用。能用 IN關(guān)鍵字的語(yǔ)句都可以轉(zhuǎn)化為使用 JOIN的語(yǔ)句,推薦使用 JOIN關(guān)鍵字。
07. WHERE 和 HAVING
WHERE和 HAVING的不同之處在于, WHERE是查找之前的限定,而 HAVING是查找之后。如果使用 HAVING,必須提前篩選字段,但 WHERE不需要。 WHERE后面不能加聚合函數(shù), HAVING后可以加聚合函數(shù)。
08. JOIN關(guān)聯(lián)表中ON,WHERE后面跟條件的區(qū)別
不管 ON上的條件是否為真都會(huì)返回 LEFT或 RIGHT表中的記錄,full則具有 LEFT和 RIGHT的特性的并集。 而 INNER JOIN沒(méi)這個(gè)特殊性,則條件放在 ON中和 WHERE中,返回的結(jié)果集是相同的。
參考原文鏈接
09. EXPLAIN 函數(shù)作用
- 表的讀取順序
- 數(shù)據(jù)讀取操作的操作類型
- 哪些索引可以使用
- 哪些索引被實(shí)際使用
- 表之間的引用
- 每張表有多少行被優(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ū)別呢?
-
CREATE INDEX必須提供索引名,對(duì)于ALTER TABLE,如果你不提供索引名,將會(huì)自動(dòng)創(chuàng)建; -
CREATE INDEX一個(gè)語(yǔ)句一次只能建立一個(gè)索引,ALTER TABLE可以在一個(gè)語(yǔ)句建立多個(gè),如:ALTER TABLEHeadOfStateADD PRIMARY KEY(ID),ADD INDEX(LastName,FirstName); - 只有
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的 UPDATE或 DELETE中子查詢不能為同一張表,可將查詢結(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
SELECT b.emp_no FROM employees bWHERE EXISTS (SELECT emp_no FROM dept_emp)
- 建立內(nèi)外關(guān)聯(lián)
SELECT b.emp_no FROM employees bWHERE EXISTS (SELECT emp_no FROM dept_emp WHERE b.emp_no=emp_no)