首頁 > 軟體

Mysql中關於on,in,as,where的區別

2023-03-21 06:02:28

Mysql on,in,as,where的區別

答:Where查詢條件,on內外連線時候用,as作為別名,in查詢某值是否在某條件裡

建立2個表:student,score

student:

score:

where

SELECT * FROM student WHERE s_sex='男'

例如:on

SELECT * FROM student LEFT JOIN score on student.s_id=score.s_id;

on和where組合:

SELECT * FROM student LEFT JOIN score on student.s_id=score.s_id WHERE s_name='趙雷' 

例如:in

SELECT * FROM score WHERE s_id in (SELECT s_id FROM student WHERE s_name='趙雷')

 

as

select * from score as a LEFT JOIN student as b on a.s_id=b.s_id where s_name='趙雷'

Mysql語句問題解決

1、left join資料篩選問題

on後面的條件只能對left join右邊的表進行篩選,左表匹配不到右表資料會在原右表位置處顯示null,left join左邊的表資料不受約束,將on後的條件加到where後會對所有資料進行篩選。

2、相同資料重複篩選使用問題

with <name> as()

mysql內可以使用with as生成臨時表,<name>為臨時表的名字,使用如下:

with arc as( 
    select id,arc.title,update_time,is_top,cId,pid,name_id from article arc where is_del = 0 
) 
select * from arc

with...as的作用範圍只有一次sql執行的時間,執行過後就不再存在,根據例子我們本要處理article表,但表裡的資料並非都是我們需要的,所繫先篩選建立了一個臨時表arc,我們會對arc進行操作。

如果只是上述例子的簡單操作是沒必要使用with...as的,但是當我們需要將article表與其他表進行聯查甚至巢狀時,會出現要多次進行is_del = 0的判斷,最終出來的sql語句可能個十分複雜,並且極易出錯,但使用arc就不需要在對資料進行重複篩選了。

with...as裡的sql可以更復雜些,比如article表裡有name_id,但更多時候我們希望使用name,我們可以預先在with...as內查詢好,再使用臨時表去做其他操作。

3、根據某個欄位排序取每個類別最後三條資料或前三條資料

這算是個比較經典的一個問題了,我初學,只會一種解題方法,但會盡力講的簡單通俗點。

範例:

select * from ( 
select cId,title,content( 
    select count(*)+1 from arc a1 where (a1.cId = a2.cId) and a1.updateTime > a2.updateTime 
)updateTimeSort from arc a2 
) a3 
where updateTimeSort <= 3 order by cId,updateTime desc

範例中cId是類別id,updateTime 是更新時間,解決問題是選取arc內每個類別最晚更新的的三條資料,就像新聞的首頁需要為每個分類選出最新的三條新聞,按照資料庫裡的資料我們可以使用排序 order by cId,updateTime desc 對資料按類別和更新時間進行排序,但去取每個類別的特定幾條資料,現有資料庫是做不到的,因此我們可以新增一個臨時欄位。

updateTimeSort 它表示的是每個類別中每個子項在這個類別中的排序,在當前問題中這個臨時欄位應該是和欄位 updateTime 相關的,根據更新時間為類別中的每個子項排出順序。

如範例程式碼,我們能找到a1和a2這兩個表,他們都是arc表的別稱,通過子查詢的形式結合在一起,以a2為主,去a1表內查詢類別和a2當前資料相同的,並且更新時間晚於a2當前資料的資料數量,能看到 count(*)+1 也就是數量加一了,不加一也可以,只是當一條資料在它所處類別更新時間最晚時count(*) 的值是0,若果使用count(*)+1 我們就可以將資料從1開始排序。

最終我們只要選取 updateTimeSort <= 3 的資料即可,如果想要篩選最早釋出的新聞也只需要將updateTimeSort 的篩選邏輯變更一下即可,在範例程式碼中即將

a1.updateTime > a2.updateTime 更改為 a1.updateTime < a2.updateTime

可以看到範例程式碼中還有一個表a3,它其實時一個臨時表,前面我們瞭解了with..as可以生成臨時表,也重這次程式碼中可以看出,臨時表也可以以另一種形式存在,with...as我們只有當sql複雜時才會使用,一般來說現在這種方式能幫我們解決不少問題了,各有優劣,看情況使用。

4、業務邏輯書寫位置問題

接觸sql多了會發現,sql其實能幫我們解決一定的業務問題,明顯的有sql的儲存過程和方法,對sql語句的批次處理其實在一定程度上幫我們解決一定的業務問題,但缺點也很明顯,當新手接觸這個專案時他很難搞清楚某個功能到底是如何實現的,不利於維護。

一般來說我們解決業務是在server層,有時會使用sql解決一些問題,但很少,在sever處理受制於計算機硬體,在資料庫處理受制於資料庫效能,相比之下,計算機硬體更易於擴充套件,因此還是不推薦大量使用sql解決問題的。

例如上個問題:根據某個欄位排序取每個類別最後三條資料或前三條資料問題,雖然問題基本解決但讓存在一些 ‘bug’,例如排序時會產生1、2、3、3、4這種排序,這是因為同個類別內有兩條資料更新時間重複了,那我們直觀想法(還是要看個人經驗值)應該是,既然問題出在資料庫,那應該在資料庫查詢的時候就解決這個問題,但事實上,讓資料庫去解決並不好解決,資料庫的強項在於各種搜尋演演算法,不在於邏輯處理,因此我們就要轉移到server層處理,會有不少人陷於這個坑,花費大量時間去找辦法讓資料庫去處理這類問題,但其實就算資料庫處理得了,它也不一定有server層處理的效率高,當然如果是為了學習更多東西,這些時間也是值得花的,但是這種解題思路還是要改變下的。將1、2、3、3、4問題交給server處理也就是利用java等高階語言處理這種問題,相信熟用這些語言的開發者解決這些問題都是小case了。

5、查詢另一表內和本表相關欄位的數量

先複習下知識:用過count函數的人都清楚一旦使用count這類聚合函數,不做其他處理資料就會歸為一行資料,但很多時候我們並不期望這樣的結果,以此就要想些辦法能用聚合函數,也能獲取很多資料,我常用的是利用group by分組。

迴歸問題,現有(現不討論表是否合理)文章表(id,title,content)有文章id,標題,文章內容三個欄位,點贊收藏表(id,arc_id,fav,like)有表id,文章id,收藏欄位(0未收藏,1收藏),點贊欄位(0未點贊,1點贊),現要查詢文章表內每篇文章的點贊收藏數,sql語句:

select art.title,art.content, 
count(case afl.fav when 1 then 1 end) as collectNum, 
count(case afl.like when 1 then 1 end) as likeNum 
from article art 
left join article_favor_like afl on afl.arc_id = art.id 
group by afl.arc_id //這是關鍵

如果沒有group by afl.arc_id 後果就是,查出來一行資料,資料還牛頭不對馬嘴,但通過對文章收藏表中的文章id進行分組就可以針對每個文章id查詢資料,這樣left join時右表就有每個文章id對相應的收藏數與點贊數,而不是表內所有點贊數和收藏數,最終資料也是我們所需的。

6、關於union的使用

例子:

select id,title,content,1 isArc from arc 
union 
select id,name,content,0 isArc from news
  • 使用union進行的是上下整合
  • 被聯合的資料列數要求一致
  • 列數相同,資料型別不同會自動進行資料型別轉換
  • 聯合後的列的名字由聯合中第一次出現的列名為依據,即使後續被聯合資料有自己的列名也不會使用,在例子中最終列名為:id,title,content,name等列名不會使用,因此使用union一般配合別名使用統一結果。
  • 有時候會區分資料是哪個表的,可以通過附加額外的欄位來區別,就像例子中的isArc欄位,news表中的isArc可以不寫,原因也就是第4條,最終列名由第一次出現的列名決定,後續資料列名有沒有都可以。

7、limit的巧用

limit一般用於分頁,功能是獲取指定區間內的資料,因此我們也可以用它來減少資料庫的查詢,例子:

select * from arc where id = 12 limit 1

資料庫查詢由索引還好,沒有索引是要遍歷資料庫的,有些資料經由條件篩選在邏輯上應該是唯一的,使用limit 1可以使資料庫查詢到該資料時不再搜尋,減少資料庫搜尋次數,但這種方法僅是一種技巧,想大幅度優化sql還要另想辦法。

8、update ignore和insert ignore的使用

//標題是唯一索引,'新標題'存在則更新操作不執行 
update ignore arc set title = '新標題' 
 
//標題是唯一索引,'標題1號'存在則插入操作不執行 
insert ignore into arc values(null,'標題1號','文章內容')

有這種需求,資料存在時不執行任何操作,不存在則更新或插入,一個辦法是使用ingore,它會忽略資料庫報錯,而資料庫執行原子操作時報錯是會回滾的,因此只要我們給資料加上主鍵或唯一索引,當被更新欄位或插入欄位與原有資料衝突時會報錯,但因為ingore會忽視這種報錯,後端也就不會報錯,sql也未執行,達到了目的,有人會對報錯敏感,其實也沒什麼,報錯也是在檢查資料是發現不合理之處給的一個提醒或警告,對資料庫無害的。

9、mysql存在更新,不存在則插入

區別於上面那個需求,這個是當插入的資料存在時更新資料,不再是不做任何操作,例子:

//本例子中title不是唯一索引,id是主鍵 
insert into arc values(1,'標題1號','文章內容') 
on duplicate key update title='標題1號'
//若要更新多個欄位使用','隔開,例:title='標題1號',content='文章內容'

在例子中,當id為1的資料存在時,更新標題和內容,不存在則插入,如果執行更新操作,未設定新值的欄位保持原來的值。

還有一個REPLACE INTO也可以達到這種效果,區別在於,REPLACE INTO更新時是先刪除後插入會破壞原有索引,id為3的資料更新時會刪除插入id為4的資料,未更新新值的欄位設定為預設值或null。

無論是兩個中的哪種方式判斷資料是否存在的依據都是主鍵和唯一索引。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com