有這樣一個表數據:
學生姓名,學生手機號,上課日期,上課科目
科目分:
語文、數學、英語、計算機
要求統計一個這樣子的結果:
學生姓名,學生手機號,第一次上課日期,迄今一共上了多少節課,上的最多的科目是,該科目一共上了幾節
本來想着簡單,那不就是group by一下,一個子查詢l不就解決了,想法如下:
select 學生姓名,學生手機號,min(上課日期),上課科目,count(上課科目) as 該科目一共上了幾節 form 表 group by 學生姓名,學生手機號,上課科目
以上面的查詢結果 as 表2,繼續查詢:
select 學生姓名,學生手機號,min(上課日期),sum(該科目一共上了幾節),max(該科目一共上了幾節),上課科目 form 表2 group by 學生姓名,學生手機號
想着,覺得這個max能找到最大數字所在的行,那么順帶返回最大數字那一行的上課科目,結果就出來了。
但是實際運行的時候發現,非聚合項,不能直接查,得使用聚合函數,比如:
這里的 學生姓名,學生手機號 是聚合項,在select的時候可以直接查詢,但是其他的非聚合項,得加上聚合函數,比如這里的 min 、sum 、max ,這些是可以的,
而這個 上課科目 非聚合項,也沒有使用聚合函數,查詢語句會報錯,
想當然的以為會找到最大行對應的上課科目也是不對的,如果真是這樣,那這句sql到底要返回 最小日期 行對應的 上課科目 還是應該返回 最大節數 對應的行里的 上課科目 呢?
不過據說呢mysql的語法是並不嚴謹的,是可以返回這個聚合函數找到的行的其他列數據,不過我並沒有去嘗試驗證。
select 學生姓名,學生手機號,min(上課日期),sum(該科目一共上了幾節),max(該科目一共上了幾節),上課科目 form 表2 group by 學生姓名,學生手機號
看來偷懶是偷不了了,只好規規矩矩的寫,3級子查詢:
這是一個查詢基表 as 表2 select 學生姓名,學生手機號,min(上課日期) as 單科最小日期,上課科目,count(上課科目) as 單科節數 form 表 group by 學生姓名,學生手機號,上課科目
在基表的基礎上 as 表3 select 學生姓名,學生手機號,min(單科最小日期) as 最小日期,sum(單科節數) as 總節數,max(單科節數) as 最大節數 form 表2 group by 學生姓名,學生手機號 在兩個子查詢的基礎上再查詢,挑出最大節數的數據行,當然,這個最大節數的不一定是單單一個科目,比如,語文、數學都是21節,都是最大節數,那么這個學生就會返回兩行結果 select aaa.學生姓名,aaa. 學生手機號,bbb. 最小日期,bbb. 總節數,aaa. 上課科目,aaa. 單科節數 form 表2 as aaa left join 表3 as bbb on aaa. 學生姓名=bbb. 學生姓名 and aaa. 學生手機號=bbb. 學生手機號 and aaa. 單科節數=bbb. 最大節數
來看個實例:
數據:
查詢代碼:
Private Sub 匯總數據() Dim Con As Object, rs As Object Set Con = CreateObject("ADODB.Connection") Con.Open "Provider=Microsoft.Ace.OLEDB.12.0;Extended Properties='Excel 12.0;hdr=no;imex=1';Data Source=" & ActiveWorkbook.FullName Dim sql As String, t As String t = "201902" & "$" Dim table1 As String, table2 As String ' 同一個人,同一門課,最小日期,上課次數 table1 = " SELECT f1, f2, min(f3) as min_f3, f4, count(1) as f4_count from [" & t & "] group by f1,f2,f4 " ' 同一個人,最小日期,上最多的次數,一共上多少次課 table2 = " select f1, f2, min(min_f3) as min_rq, max(f4_count) as f4_max, sum(f4_count) as f4_sum from (" & table1 & ") group by f1,f2 " ' 姓名 電話 首次上課時間 總上課次數 上得最多的課程(, where left join on 兩種方式都是可以的) sql = " SELECT distinct a.f1, a.f2, b.min_rq, b.f4_sum, a.f4, a.f4_count from (" & table2 & ") as b, (" & table1 & ") as a " sql = sql & " WHERE a.f1 = b.f1 and a.f2 = b.f2 and a.f4_count = b.f4_max " ' sql = " SELECT distinct a.f1, a.f2, b.min_rq, b.f4_sum, a.f4, a.f4_count from (" & table2 & ") as b left join (" & table1 & ") as a " ' sql = sql & " on a.f1 = b.f1 and a.f2 = b.f2 and a.f4_count = b.f4_max " Set rs = Con.Execute(sql) Sheets.Add After:=Sheets(Sheets.Count) For i = 0 To rs.fields.Count - 1 Cells(1, i + 1) = rs.fields(i).Name Next Cells(2, 1).CopyFromRecordset rs rs.Close: Set rs = Nothing Con.Close: Set Con = Nothing End Sub
結果: