多表關聯小記

前言

最近工作中接觸了多表關聯,有所感悟,想了很久,在這裏將自己理解記錄下來。不管對錯,形成觀點了,等以後再推翻,這看起來是件很有意思的事情。對於多表關聯我非常的畏懼,而之前的工作也就是改改bug,在寫sql碰到不多,碰到的也是非常簡單。這次換了一個新的環境,對寫sql要求很高,我意識到有必要先建立sql這方面自己的認識了。看起來這些總結不全面,描述存在錯誤,可意會不可言傳,還不如多實踐。但有自己觀點即使錯誤的,心中也安

正文

一張表A 數量爲n,表B數量爲m,笛卡爾積以後數量變成了 n * m,這n*m的數據肯定不是期望中的。兩張關聯表需要關聯,就存在兩張表對應的column,這些column可能是一個,可能是多個,不論多少個,一個有一個的期望需求,多個有多個的期望需求,問問自己,做一個關聯,這個範圍得到的數據,是不是自己想要的,不想要就再用另外的對應column再次剔除,縮小數據的範圍。反正一句話,笛卡爾積得到的結果是雜亂的,當你剔除過數據了,這些數據就滿足某種需求了,我們要做的就是確認這些是不是自己期望結果
觀點一、多表查詢就是笛卡爾積,然後剔除毫無聯繫的數據
例子
兩張表
項目表
這裏寫圖片描述
職工表
這裏寫圖片描述

我現在要做的就是對這兩張表做關聯
很疑惑,這兩張表好像不是一對多,有點多對多的味道,可以關聯嗎?得到的結果是什麼? 理論上有對應關係,都可以關聯,只是結果能不能符合期望的,就另作處理了

SELECT obj.*,worker.*
FROM object obj, worker worker
WHERE obj.teamid = worker.teamid

對笛卡爾積做第一步剔除,obj.teamid = worker.teamid 做剔除什麼意思呢?
1、obj 一行數據與worker一行數據連接,形成新的一行,可以理解爲,一個項目所執行的團隊下面的所有員工。

現在的需求是:一張頁面顯示項目信息,現在項目信息表裏面字段信息太少了,要求我們關聯其它表,查詢這個項目所執行團隊的人數。

那麼上面的查詢可以滿足需求嗎? 答案是否定的,我們要求頁面每一行數據代表一個項目,這一行後面一些字段只是擴展的信息。而上面查詢出來 項目信息+A團隊B成員小張爲一行,項目信息+A團隊C成員爲一行,這些數據放到頁面上,那麼那個頁面需要的信息完全變了。如何解決?
觀點二、分組、子查詢在多表關聯中非常有用。子查詢可以將看起來與匹配表毫無關係的表與一些表先關聯,得到結果集,然後在這些結果集中存在一個與匹配表有對應關係的字段,再進行笛卡爾積,作爲剔除條件。 分組可以將關聯,並剔除毫無關係的數據後,多出來的數據合併,使最後的結果集數量與匹配表一致
我把sql寫了一下

SELECT obj.*,employee.nums
FROM object obj
left join
(select teamid, count(*) nums
 from worker worker group by teamid
)  employee on employee.teamid = obj.teamid

這裏需要一個子查詢,取到精心設計得到的結果集,通過分組,我們可以將後面因爲teamid導致的fork,合在一起,這樣就形成了一對一的關係。媽媽再也不擔心通過關聯得到的數據莫名其妙,而且數量和匹配表(頁面要查的數據的表,叫什麼沒關係,名字只是一個代號)
不一致了(本來匹配表期望有100條,關聯一下1000條了,這1000條不能說錯,只是不是這裏期望中的數據)。

還好上面要求查詢的是人數,可以通過分組來解決。如果查詢所有成員信息,那麼我看是想多了,一行數據代表是項目,你能在一行中fork來存放各個成員信息嗎? 這是不可能的。那麼何必糾結呢,我們轉換一下,將worker作爲匹配表,一行表示員工的信息 + 擴展就是這個員工所作的這個項目的信息,這裏注意的是這個項目是這個員工所做的唯一一個項目,如果這個員工做過多個項目,又回到上面的情況了,又有fork了。就好比一條直線的路,走着走着,就出現分叉路口了(真有fork,那麼只能用分組來合併了,兩表形成多對一,一對一的關係)
觀點三:需求要求頁面每一行代表表A的每一行,後面擴展一些信息,那麼以這表A作爲匹配表,後面的擴展表要求與表A形成一對多,一對一關係,避免分叉,避免不免就分組,變成一對多,一對一

2、上面也可以理解爲:worker表每一行數據與Object表每一行關聯一起 意思是:每一個員工所在的團隊所做過的所有的項目。其實查詢結果都是一樣的,我在做關聯的時候腦子裏從第一張表第一行與第二張表的每一行連在一起,成爲新的一行。然後解讀它的意思。含義不一樣,但是結果是一樣的

再次對下面sql改造

SELECT obj.*,worker.*
FROM object obj, worker worker
WHERE obj.teamid = worker.teamid

一行關聯數據這裏理解成:一個項目所執行團隊的一個員工的信息
第一行是這個項目執行團隊A員工的信息,第二行是這個項目執行團隊B員工的信息,也就是所有項目所執行團隊的所有成員信息,這個範圍符合需求嗎?


需求:列出所有項目信息,擴展列出項目經理信息


那麼我們還需要將範圍縮小
觀點四、關聯表剔除毫無關係的數據以後,其實能滿足某種需求了,剩下的就是範圍縮小的事情了,讓它適合當前的需求

SELECT obj.*,worker.*
FROM object obj, worker worker
WHERE obj.teamid = worker.teamid
and obj.principal = worker.name

列出了每一個項目信息和這個項目的負責人信息


下面擴展一下,有如下的任務表
這裏寫圖片描述
在上面關聯查詢繼續關聯這個任務表,比如如下的需求


需求:找出項目信息,後面擴展字段有:這個項目所在團隊所有成員的數量,所有的任務


下面是之前寫的sql

SELECT obj.*,employee.nums
FROM object obj
left join
(select teamid, count(*) nums
 from worker worker group by teamid
)  employee on employee.teamid = obj.teamid

可以將上面的結果集,想成存放到臨時表temp中,現在temp需要和task表做關聯,task與temp是多對一的關係,一條temp數據面臨多個分叉路口,所以這裏將需求改成顯示任務數量,這樣就可以用分組,將分叉路口合在一起
觀點五、多表關聯是可插拔式的,只要有幾張表存在聯繫即可
現在我們接上一個子查詢,很簡單,只要跟上一個left on + 子查詢 + 剔除不符合需求的數據
先寫第三個子查詢

left join (
  select workid ,count(*) counts
  from task
  group by workid
) tk on tk.workid = employee.id

發現分組原因,我只能包含task分組字段workid字段,那麼我這個結果集,拿什麼與上面的temp中的數據做關聯? 發現沒有可剔除的條件 temp一行的字段有object所有字段 + teamid + nums ,根本就沒有workid
解決,沒辦法,這個表是我之前胡亂設計的,只能往object表填字段了
我在object表添加了如下字段
這裏寫圖片描述
需求更改:

找出項目信息,後面擴展字段有:這個項目所在團隊所有成員的數量,以及這個項目的項目經理所有的任務
sql如下

SELECT obj.*,employee.nums,tk.tk.counts
FROM object obj
left join
(select teamid, count(*) nums
 from worker worker group by teamid
)  employee on employee.teamid = obj.teamid
left join (
  select workid ,count(*) counts
  from task
  group by workid
) tk on tk.workid = obj.workerid

最後總結一下:多張表關聯,可以將每個表每一行數據連在一起,想想會不會中途出現交叉路口,這些交叉路口導致數量結果增多是不是滿足需求? 不滿足,能不能通過分組來合併? 多思考
觀點六、多表關聯,有數據數量不斷增多的可能,要非常明確,一條數據代表的是什麼

胡言亂語一番,但願以後回過頭查閱能看懂,一個程序員描述問題這個能力需要的,連話都講不清楚,可知邏輯性多糟糕,努力克服吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章