最近遇到了乙個很是動態化的查詢需求,要求的列數是動態載入的,而不是固定的列數,並且列內容的由來都是通過動態聯查得到的,所以很是棘手,需要用到行轉列的這種sql查詢方式。
行轉列的用法有的時候體現在乙個第三條件介入問題的關聯,我們都知道,我們做查詢的時候,實際上查詢出來的是一張表,直觀來看是乙個二維的資料結構,可以包含兩種關係在其中,分別對應兩種條件關聯產生,但是實際上我們做出的查詢結果,在縱向上總是保持為是乙個資料集的計數功能,也就是說我們的條件關係是建立在乙個一維線性關聯上面的,但是我們又可以讓我們的表可以表達更多的東西是為什麼呢?是因為我們在這個一維的關係上疊加了很多不同的,但是有關係(依賴)的字段關聯,其中的每一項都或多或少和前面的字段是有關係才能出現在後面的,但是什麼時候用到行轉列呢?其中一種情況就是我們所要展示的列的資料,是以一種交叉關係存在於某乙個表的一列中的複數項利用的關係的字段,這個時候我們才會用到行轉列這個思想。
舉乙個最最簡單的例子,就是學生,科目,分數這個例子:
學生表: 學號
姓名性別
年齡01小明男
1202小芳女
13 科目表:
代號名稱
老師01
語文王老師
02數學
***
分數表:
id學號
科目代號
分數01
0101
9802
0102
8703
0201
7604
020288
這樣的結構,當我想要知道任何乙個人的各科成績的時候,需要聯查這幾張表,這個時候如果每個學生可能對應的科目是有差異的時候,我們想要得到成績的列數也是不同的了,這個時候我們需要把課程作為列新增到學生表後面作為聯查的項來進行查詢。
假設,我們查詢的所有學生上的課程都是一樣的,而且不會變化,那麼我們用如下的sql語句進行查詢就可以得到結果:
select st.stuid, st.stunm,
max(case c.coursenm when '大學語文' then s.scores else 0 end ) '大學語文',
max(case c.coursenm when '新視野英語' then ifnull(s.scores,0) else 0 end ) '新視野英語',
max(case c.coursenm when '離散數學' then ifnull(s.scores,0) else 0 end ) '離散數學',
max(case c.coursenm when '概率論與數理統計' then ifnull(s.scores,0) else 0 end ) '概率論與數理統計',
max(case c.coursenm when '線性代數' then ifnull(s.scores,0) else 0 end ) '線性代數',
max(case c.coursenm when '高等數學(一)' then ifnull(s.scores,0) else 0 end ) '高等數學(一)',
max(case c.coursenm when '高等數學(二)' then ifnull(s.scores,0) else 0 end ) '高等數學(二)'
from student st
left join score s on st.stuid = s.stuid
left join courses c on c.courseno = s.courseno
group by st.stuid
但是如果科目是隨著年級的變化而變化的話,寫到sql中就不是很明智的選擇了。這個時候就需要用到動態的查詢了。
我們可以看到,建立列的語句其實就是幾個重複的語句,只要把他們變成動態的就可以了。
max(case c.coursenm when '大學語文' then s.scores else 0 end ) '大學語文',
max(case c.coursenm when '新視野英語' then ifnull(s.scores,0) else 0 end ) '新視野英語',
max(case c.coursenm when '離散數學' then ifnull(s.scores,0) else 0 end ) '離散數學',
max(case c.coursenm when '概率論與數理統計' then ifnull(s.scores,0) else 0 end ) '概率論與數理統計'
於是有了下面的查詢方式:
select st.stuid, st.stunm,
( select
group_concat(distinct
concat(
'max(if(c.coursenm = ''',
c.coursenm,
''', s.scores, null)) as ',
c.coursenm))
from courses c
)from student st
left join score s on st.stuid = s.stuid
left join courses c on c.courseno = s.courseno
group by st.stuid;
但是這樣查詢是不行的,這樣的話會把整個大括號中的內容算作是一列的內容,導致輸出了sql語句的一部分,所以這裡需要分開進行書寫查詢:
set @sql = null;
select
group_concat(distinct
concat(
'max(if(c.coursenm = ''',
c.coursenm,
''', s.scores, 0)) as ''',
c.coursenm, ''''
)) into @sql
from courses c;
set @sql = concat('select st.stuid, st.stunm, ', @sql,
' from student st
left join score s on st.stuid = s.stuid
left join courses c on c.courseno = s.courseno
group by st.stuid');
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;
這樣寫就可以了,通過我自己的實踐,是可以查詢出來的,一下為我的查詢語句:
set @sql = null;
set @goods_id = '1';
select
group_concat(distinct
concat(
'max(if(bgp.property_name = ''',
bgp.property_name,
''', bgpi.item_name, 0)) as ''',
bgp.property_name, ''''
)) into @sql
from
busi_goods_property as bgp;
set @sql = concat('select bgs.sku_num,bgs.sku_price,
bgs.sku_stock,
bgs.sku_stock_warning, ', @sql,
' from
busi_goods_sku as bgs
left join busi_goods_sku_property as bgsp on bgs.sku_id=bgsp.sku_id
left join busi_goods_property as bgp on bgsp.property_id=bgp.property_id
left join busi_goods_property_item as bgpi on bgsp.item_id=bgpi.item_id
where bgs.goods_id = ''', @goods_id, '''
group by bgs.sku_num');
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;
這裡需要注意的是,在大查詢的末尾,必須有那個group by的語句,否則查詢只會查詢出一條結果,並且資料是不準確的。這裡主要是因為在查詢資料的時候是以我們的最外層分組為依據來查詢的裡面動態列的內容,所以需要對外層進行分組之後才可以知道裡面的資料對應關係。
讓MySQL查詢更加高效 對查詢進行重構
在優化有問題的查詢時,目標應該是找到乙個更優的方法獲得實際需要的結果,而不是一定總是要求從mysql獲取一模一樣的結果集 設計查詢的時候一定需要考慮的問題就是,是否需要將乙個複雜的查詢分成多個簡單的查詢。雖然在傳統實現中,總是強調需要在資料庫層完成盡可能多的工作,這是因為在過去總是認為網路通訊 查詢...
SQL進行行列轉換
假設現在有這樣一張表 create table dbo relconlist listid allint identity 1,1 not null listfkmainid varchar 20 collate chinese prc ci as not null listfkrelid varc...
Python OpenCV進行行人檢測
應用非極大抑制方法,可排除候選的重疊檢測 我執行的環境為python3.6 anaconda3 opencv3,ide pycharm 1.其中如果安裝anaconda3就可以少安裝很多庫 2.如果安裝了anaconda3,就只需要配置乙個庫imutils 3.imutils安裝方法 pip ins...