1. 程式人生 > >mysql縱錶轉換為橫表進行多表之間的關聯查詢

mysql縱錶轉換為橫表進行多表之間的關聯查詢

1、資料庫的表可以分為兩類:縱表與橫表

縱表:表中欄位與欄位的值採用key——value形式,即表中定義兩個欄位,其中一個欄位裡存放的是欄位名稱,另一個欄位中存放的是這個欄位名稱代表的欄位的值。

例如,下面這張project_audit_log表,其中date_type欄位表示為什麼時間型別,後面的date_value表示這個時間的值

橫表:所有的欄位都在表結構中定義出來。如果把上面表的date_type與date_value欄位轉換為shelve_date,offShelve_date,

advance_finish_date這三個欄位,那這就是一張橫表。

優缺點:橫表的表結構更加的清晰明瞭,關聯查詢的一些sql語句也更容易,方便易於後續開發人員的接手,但是如果欄位不夠,需要新增欄位,會改動表結構。

 縱表擴充套件性更高,如果要增加一個欄位,不需要改變表結構,但是一些關聯查詢會更加麻煩,也不便於維護與後續人員接手。

平常開發,儘量能用橫表就不要用縱表,維護成本比較高昂,而且一些關聯查詢也很麻煩。

2、縱表如何轉換為橫表

(1)第一步,我們先把這些欄位名以及相應欄位的值從縱表中取出來

select b.project_id,b.version,
(case b.date_type when 'shelveDate' then b.date_value else '' end )shelveDate,
(case b.date_type when 'offShelveDate' then b.date_value else '' end)offShelveDate,
(case b.date_type when 'advanceFinishDate' then b.date_value else '' end) advanceFinishDate
from project_audit_log b;

結果:

採用case語句,成功把欄位從縱表中取出,但是此時仍算不上一個橫表,我們需要把相同project_id和version的行合併(這兩個欄位合起來是確保表中資料唯一性的)。

注意:這裡需要取出每一個欄位,都要case一下,有多少個欄位,就需要多少次case語句。因為一個case語句,遇到符合條件的when語句之後,後面的會不再執行。

(2)分組,合併相同行,生成橫表

select b.project_id,b.version,
max(case b.date_type when 'shelveDate' then b.date_value else '' end )shelveDate,
max(case b.date_type when 'offShelveDate' then b.date_value else '' end)offShelveDate,
max(case b.date_type when 'advanceFinishDate' then b.date_value else '' end) advanceFinishDate
from project_audit_log b group by b.project_id,b.version;

注意:這裡採用group by 分組的時候,需要給欄位加上max函式。用group by 分組的時候,一般搭配聚合函式使用,常見的聚合函式:

  • AVG() 求平均數
  • COUNT() 求列的總數
  • MAX() 求最大值
  • MIN() 求最小值
  • SUM() 求和

這裡不使用max聚合函式的話,會從分組裡面顯示第一次出現的欄位值,去掉max函式之後的sql:

select b.project_id,b.version,
(case b.date_type when 'shelveDate' then b.date_value else '' end )shelveDate,
(case b.date_type when 'offShelveDate' then b.date_value else '' end)offShelveDate,
(case b.date_type when 'advanceFinishDate' then b.date_value else '' end) advanceFinishDate
from project_audit_log b group by b.project_id,b.version;

查詢的結果:

(3)縱表變成橫表之後,就可以很方便的進行關聯查詢以及關於縱表字段的條件查詢,比如,另有一張表project_info ,與project_audit_log關聯,並且查出shelveDate時間大於2018-08-03 16:23:59與offShelveDate小於2018-08-06 15:12:22

select a.id,a.version,a.project_name,e.shelveDate,e.offShelveDate,e.advanceFinishDate
from project_info a left join 
(select b.project_id,b.version,
max(case b.date_type when 'shelveDate' then b.date_value else '' end )shelveDate,
max(case b.date_type when 'offShelveDate' then b.date_value else '' end)offShelveDate,
max(case b.date_type when 'advanceFinishDate' then b.date_value else '' end) advanceFinishDate
from project_audit_log b group by b.project_id,b.version) e on a.id = e.project_id and a.version = e.version where e.shelveDate >= '2018-08-03 16:23:59' and e.offShelveDate <= '2018-08-06 15:12:22';

(4)採用GROUP_CONCAT,進行欄位合併,合成一個橫表

select a.project_id,a.version,GROUP_CONCAT(a.date_type,a.date_value) date from project_audit_log a  GROUP BY a.project_id,a.version;

然後進行與其他表的關聯查詢,但是這樣的做法,對於縱表中的欄位條件查詢也不方便,如果我們要篩選出shelveDate與offShelveDate或者advanceFinishDate條件,也挺不方便的,比較適合於不對縱表字段進行條件查詢,只與其它表關聯查詢出縱表資訊。