查詢(xún)是mysql中的最頻繁操作,它也是用于構(gòu)建delete、update的基礎(chǔ);而查詢(xún)處理可分為邏輯查詢(xún)和物理查詢(xún)。今天我們就來(lái)給大家詳細(xì)介紹一下邏輯查詢(xún),希望對(duì)大家有所幫助!
在mysql中,查詢(xún)是用于構(gòu)建DELETE、UPDATE的基礎(chǔ),因?yàn)槟阋獎(jiǎng)h除或者更新他們時(shí),首先就是要查出這些記錄,所以SELECT顯的尤為重要,對(duì)于查詢(xún)處理,可以分為邏輯查詢(xún)和物理查詢(xún),邏輯查詢(xún)表示執(zhí)行SELECT語(yǔ)句時(shí)應(yīng)該產(chǎn)生什么樣的結(jié)果,而物理查詢(xún)表示MySQL如何得到這個(gè)結(jié)果的。【相關(guān)推薦:mysql視頻教程】
本章來(lái)說(shuō)一下邏輯查詢(xún)。
在SQL語(yǔ)句中,最先處理的就是FROM語(yǔ)句,最后執(zhí)行的是LIMIT語(yǔ)句,如果把所有的語(yǔ)句都用上,如GROUP BY、ORDER BY,那么大致可以分為10個(gè)步驟,如下所示,每個(gè)操作都會(huì)產(chǎn)生一張?zhí)摂M表。
(7)?select?(8)distinct<select_list> (1)?from?<left> (3)?<join_type>?join?<right_table> (2)????on (4)?where? (5)?group?by (6)?having (9)?order?by (10)?limit</right_table></join_type></left></select_list>
下面通過(guò)一個(gè)實(shí)際例子來(lái)分析一下,首先創(chuàng)建兩張表,用戶(hù)和訂單。
mysql>?create?table?user?(userId?int(11),userName?varchar(255),city?varchar(255),?primary?key?(userId)); Query?OK,?0?rows?affected,?1?warning?(0.05?sec) mysql>?create?table?orders(orderId?int(11)?,userId?int(11)?,primary?key?(orderId)); Query?OK,?0?rows?affected,?2?warnings?(0.05?sec)
插入數(shù)據(jù)。
insert?user?values(1,"張三","內(nèi)蒙"); insert?user?values(2,"李四","內(nèi)蒙"); insert?user?values(3,"王五","北京"); insert?user?values(4,"迪迦","西藏"); insert?user?values(5,"金甲戰(zhàn)士","內(nèi)蒙"); insert?orders?values(10001,1); insert?orders?values(10002,1); insert?orders?values(10003,4); insert?orders?values(10004,1); insert?orders?values(10005,1); insert?orders?values(10006,4); insert?orders?values(10007,2);
好,現(xiàn)在來(lái)查詢(xún)一下來(lái)自?xún)?nèi)蒙,且訂單數(shù)量小于3的用戶(hù),SQL如下。
mysql>?select?userName,count(orders.orderId)?as?total?from?user? left?join?orders?on?user.userId?=?orders.userId? where?city="內(nèi)蒙"? group?by?user.userId? having?count(orders.orderId)<p>有數(shù)據(jù)有SQL,下面分析一下具體流程。</p><p><strong><span style="font-size: 18px;">1. 笛卡爾乘積</span></strong></p><p>首先要做的是對(duì)FROM語(yǔ)句前后的兩張表進(jìn)行笛卡爾乘積,那么什么是笛卡爾乘積?舉個(gè)例子來(lái)說(shuō),假設(shè)集合A={a, b},集合B={0, 1, 2},則兩個(gè)集合的笛卡爾積為{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。</p><p>所以,對(duì)應(yīng)上面的數(shù)據(jù),最終會(huì)產(chǎn)生一張?zhí)摂M表VT1,他將包含35行數(shù)據(jù),具體數(shù)據(jù)如下所示。</p>
userId | userName | city | orderId | userId |
---|---|---|---|---|
1 | 張三 | 內(nèi)蒙 | 10001 | 1 |
1 | 張三 | 內(nèi)蒙 | 10002 | 1 |
1 | 張三 | 內(nèi)蒙 | 10003 | 4 |
1 | 張三 | 內(nèi)蒙 | 10005 | 1 |
1 | 張三 | 內(nèi)蒙 | 10006 | 1 |
1 | 張三 | 內(nèi)蒙 | 10005 | 4 |
1 | 張三 | 內(nèi)蒙 | 10007 | 2 |
……………… | ||||
5 | 金甲戰(zhàn)士 | 內(nèi)蒙 | 10001 | 1 |
5 | 金甲戰(zhàn)士 | 內(nèi)蒙 | 10002 | 1 |
2. ON過(guò)濾器
下一步,通過(guò)ON后面的添加過(guò)濾掉不需要的數(shù)據(jù),在上述SQL中,條件是user.userId = orders.userId ,所以通過(guò)上面生成的虛擬表VT1,除去不相關(guān)的數(shù)據(jù),生成新的虛擬表VT2,最終的結(jié)果如下。
+--------+--------------+--------+---------+--------+ |?userId?|?userName?????|?city???|?orderId?|?userId?| +--------+--------------+--------+---------+--------+ |??????1?|?張三?????????|?內(nèi)蒙???|???10005?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10004?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10002?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10001?|??????1?| |??????2?|?李四?????????|?內(nèi)蒙???|???10007?|??????2?| |??????3?|?王五?????????|?北京???|????NULL?|???NULL?| |??????4?|?迪迦?????????|?西藏???|???10006?|??????4?| |??????4?|?迪迦?????????|?西藏???|???10003?|??????4?| |??????5?|?金甲戰(zhàn)士?????|?內(nèi)蒙???|????NULL?|???NULL?| +--------+--------------+--------+---------+--------+
3.添加外部行
這一步只有在連接類(lèi)型為OUTER JOIN才發(fā)生。
LEFT OUTER JOIN把左表記為保留表,RIGHT OUTER JOIN把右表作為保留表,F(xiàn)ULL OUTER JOIN表示都作為保留表,添加外部行的工作就是在上一步的基礎(chǔ)上添加保留表中被過(guò)濾條件過(guò)濾掉的數(shù)據(jù),非保留表的數(shù)據(jù)被賦值NULL。
最終生成下面的結(jié)果,記為虛擬表VT3。
+--------+--------------+--------+---------+--------+ |?userId?|?userName?????|?city???|?orderId?|?userId?| +--------+--------------+--------+---------+--------+ |??????1?|?張三?????????|?內(nèi)蒙???|???10005?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10004?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10002?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10001?|??????1?| |??????2?|?李四?????????|?內(nèi)蒙???|???10007?|??????2?| |??????3?|?王五?????????|?北京???|????NULL?|???NULL?| |??????4?|?迪迦?????????|?西藏???|???10006?|??????4?| |??????4?|?迪迦?????????|?西藏???|???10003?|??????4?| |??????5?|?金甲戰(zhàn)士?????|?內(nèi)蒙???|????NULL?|???NULL?| +--------+--------------+--------+---------+--------+
4. WHERE過(guò)濾器
這一步很簡(jiǎn)單,條件為city=”內(nèi)蒙” ,即只保留下city為內(nèi)蒙的列,并生成新的虛擬表VT4。最終結(jié)果如下。
+--------+--------------+--------+---------+--------+ |?userId?|?userName?????|?city???|?orderId?|?userId?| +--------+--------------+--------+---------+--------+ |??????1?|?張三?????????|?內(nèi)蒙???|???10005?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10004?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10002?|??????1?| |??????1?|?張三?????????|?內(nèi)蒙???|???10001?|??????1?| |??????2?|?李四?????????|?內(nèi)蒙???|???10007?|??????2?| |??????5?|?金甲戰(zhàn)士?????|?內(nèi)蒙???|????NULL?|???NULL?| +--------+--------------+--------+---------+--------+
5. GROUP BY 分組
這步將上一個(gè)步驟進(jìn)行分組,并生成新的虛擬表VT5,結(jié)果如下。
+--------+--------------+--------+ |?userId?|?userName?????|?city???| +--------+--------------+--------+ |??????1?|?張三?????????|?內(nèi)蒙???| |??????2?|?李四?????????|?內(nèi)蒙???| |??????5?|?金甲戰(zhàn)士?????|?內(nèi)蒙???| +--------+--------------+--------+
6.HAVING篩選
分完組,我們就可以篩選了,選出count(orders.orderId)
|?userId?|?userName?????|?city???|?count(orders.orderId)?| +--------+--------------+--------+-----------------------+ |??????2?|?李四?????????|?內(nèi)蒙???|?????????????????????1?| |??????5?|?金甲戰(zhàn)士?????|?內(nèi)蒙???|?????????????????????0?| +--------+--------------+--------+-----------------------+
7.處理SELECT列表
雖然SELECT是查詢(xún)中最先被指定的部分,但是直到這里才真正進(jìn)行處理,在這一步,將SELECT中指定的列從上一步產(chǎn)生的虛擬表中選出。
8.應(yīng)用DISTINCT
如果查詢(xún)語(yǔ)句中存在DISTINCT子句,則會(huì)創(chuàng)建一張內(nèi)存臨時(shí)表,這張內(nèi)存臨時(shí)表的表結(jié)構(gòu)和上一步產(chǎn)生的虛擬表一樣,不同的是對(duì)進(jìn)行DISTINCT操作的列增加了一個(gè)唯一索引,以此來(lái)去除重復(fù)數(shù)據(jù)。
另外對(duì)使用了GROUP BY語(yǔ)句的查詢(xún),再使用DISTINCT是多余的,因?yàn)橐呀?jīng)進(jìn)行了分組,不會(huì)移除任何行。
9.排序和LIMIT
最后就是排序,返回新的虛擬表。結(jié)果如下。
+--------------+-------+ |?userName?????|?total?| +--------------+-------+ |?李四?????????|?????1?| |?金甲戰(zhàn)士?????|?????0?| +--------------+-------+
但是在本例子中沒(méi)有使用到LIMIT,如果使用到了,那么則從選出指定位置開(kāi)始的指定行數(shù),
原文地址:https://juejin.cn/post/7000739902937628679作者:i聽(tīng)風(fēng)逝夜
更多編程相關(guān)知識(shí),請(qǐng)?jiān)L問(wèn):mysql視頻教程!!