我們通常爲分組查詢提出其他特別的要求,例如我想獲得每個用戶最後一次評論的時間,以及每個用戶最後一次的評論的ID。看上去好像這個要求和合理,但是我們卻無法只單單用聚合函數去實現。
以下這個例子是獲得各個管理員最後一次提交代碼的時間:
select a.username,max(c.commit_date) from commit_recode c
join admins a using(admin_id) group by a.admin_id;
回到剛剛那個問題,我們如何去獲得這個最後一次提交的代碼記錄的ID呢?通常我們會用如下的方式去做:
select a.username,max(c.commit_date),max(c.recode_id)
from commit_recode c join admins a using(admin_id) group by a.admin_id;
貌似很合理,但是你能確保最後一次提交代碼的記錄就是ID最大的記錄嗎?貌似也不太能保證,每一種情況都是ID最大就是最後一條提交的記錄,畢竟是否爲最後一條提交我們還是要看記錄時間的字段,所以這種方式也略顯雞肋。
其實實現這種需求不一定要用集合函數,其實有非常多的方式方法去實現。
首先,我先貼出一下需要使用到的兩張表的表結構:
insert into admins(username,userpwd,image_path)
values
('TONY','PWD','abc.jpg'),
('CHAO','PWD',NULL),
('ADMIN','PWD','admin.jpg'),
('YAN','PWD','YAN.jpg');
create table commit_recode(recode_id int primary key auto_increment,recode_text varchar(100),commit_date date,admin_id int,
foreign key (admin_id) references admins(admin_id));
insert into commit_recode(recode_text,commit_date,admin_id)
values
('ADMIN: FIRST COMMIT CODE!','2017-1-8',3),
('TONY: FIRST COMMIT CODE!','2017-1-5',1),
('ADMIN: LAST COMMIT CODE!','2017-8-8',3),
('TONY: LAST COMMIT CODE!','2017-3-5',1),
('ADMIN: ONE MORE COMMIT CODE!','2017-8-8',3),
('TONY: ONE MORE COMMIT CODE!','2017-3-5',1);
第一種方式:使用子查詢
select a1.username,c1.commit_date,c1.recode_id from commit_recode c1
join admins a1 using(admin_id)
where not exists (
select * from commit_recode c2 join admins a2 using(admin_id)
where a1.admin_id = a2.admin_id and c1.commit_date < c2.commit_date
);
查詢結果如下:
可以看到我查出來4條數據,因爲每個管理員最後一天都提交了兩次代碼。之後我們會嘗試獲得最後一天最後ID最大的記錄。
第二種方式:衍生表
select a1.username,c1.commit_date,max(c1.recode_id) from commit_recode c1
join admins a1 on c1.admin_id = a1.admin_id
left join (
commit_recode c2 join admins a2 on c2.admin_id = a2.admin_id ) on
( (c1.admin_id = c2.admin_id and c2.commit_date > c1.commit_date) )
where c2.recode_id is null group by a1.username,c1.commit_date;
不着急,慢慢看總會看懂的。但是這裏已經做獲得最大ID作爲最後一次提交的記錄,但是使用max(c1.recode_id)並不是唯一的選擇,看看以下這個方式:
select a1.username,c1.commit_date,c1.recode_id from
commit_recode c1 join admins a1 on c1.admin_id = a1.admin_id
left join (commit_recode c2 join admins a2 on c2.admin_id = a2.admin_id ) on
(
(c1.admin_id = c2.admin_id and c2.commit_date > c1.commit_date)
or
(c1.admin_id = c2.admin_id and
c2.commit_date = c1.commit_date and
c1.recode_id < c2.recode_id)
)
where c2.recode_id is null;
最後一種方法:外聯查詢
select m.username,m.last_commit_date,max(c1.recode_id) as recode_id
from commit_recode c1 join admins a1 using(admin_id) JOIN (
select a2.username username,max(c2.commit_date) as last_commit_date
from commit_recode c2 join admins a2 using(admin_id) group by a2.admin_id
) as m
on m.last_commit_date = c1.commit_date group by m.username,m.last_commit_date;
其實使用SQL查詢有非常多的方法,這個是我在複習SQL的時候寫的一些乾貨。