基本的聚合

聚合是一个非常实用的查询。

SELECT foo, MIN(bar) AS bar 
FROM tbl 
GROUP BY foo

在表tbl中,根据列foo分组,选择列foo及列bar中最小的值。

SELECT foo, MAX(bar) AS Count 
FROM tbl 
GROUP BY foo 
ORDER BY Count DESC;

在表tbl中,根据列foo分组,选择列foo及列bar中最大的值count,最按count降序排列。

也可以通过子查询来实现:

SELECT a.foo, a.bar 
FROM tbl a 
JOIN ( 
  SELECT foo, MAX(bar) AS Count 
  FROM tbl 
  GROUP BY foo 
) b ON a.foo=b.foo AND a.bar=b.count 
ORDER BY a.foo, a.bar;

MySQL引入了SQL扩展GROUP_CONCAT(),它简化了分组后列项的工作。例如,给出列suppliers和parts的表:

CREATE TABLE supparts(supID char(2),partID char(2)); 
INSERT INTO supparts VALUES 
('s1','p1'),('s1','p2'),('s1','p3'),('s1','p4'),('s1','p5'),('s1','p6'), 
('s2','p1'),('s2','p2'),('s3','p2'),('s4','p2'),('s4','p4'),('s4','p5');

列出每个parts的suppliers:

SELECT partID,GROUP_CONCAT(supID ORDER BY supID) AS Suppliers  
FROM supparts  
GROUP BY partID; 

+--------+-------------+
| partID | Suppliers   |
+--------+-------------+
| p1     | s1,s2       |
| p2     | s1,s2,s3,s4 |
| p3     | s1          |
| p4     | s1,s4       |
| p5     | s1,s4       |
| p6     | s1          |
+--------+-------------+

当有数个表被join的时候,对于初学者来说,对于复杂的问题可能会感觉到无从下手。假设,对于这个schema,你被告知要检索"computer desk"销售最多的销售人员

drop table if exists salespersons, orders, orderlines, products; 
create table salespersons(salespersonid int,name char(8)); 
insert into salespersons values(1,'Sam'),(2,'Xavier'); 
create table orders(orderid int,salespersonid int); 
insert into orders values(1,1),(2,1),(3,1),(4,2),(5,2); 
create table orderlines(lineid int,orderid int,productid int,qty int); 
insert into orderlines values(1,1,1,1),(2,1,1,2),(3,2,2,1),(4,3,1,1),(5,4,1,1),(6,5,2,2); 
create table products(productid int,name char(32)); 
insert into products values(1,'computer desk'),(2,'lamp'),(3,'desk chair');

使用多表连接(join):

select s.name, p.name, l.qty 
from salespersons s 
join orders       o using(salespersonid) 
join orderlines   l using(orderid) 
join products     p using(productid) 
+--------+---------------+------+ 
| name   | name          | qty  | 
+--------+---------------+------+ 
| Sam    | computer desk |    1 | 
| Sam    | computer desk |    2 | 
| Sam    | lamp          |    1 | 
| Sam    | computer desk |    1 | 
| Xavier | computer desk |    1 | 
| Xavier | lamp          |    2 | 
+--------+---------------+------+

现在, 我们需要筛选产品“computer desk“,加入聚合,找到销量最好的售货员:

select s.name, sum(l.qty) as n      -- sum quantities 
from salespersons s 
join orders       o using(salespersonid) 
join orderlines   l using(orderid) 
join products     p using(productid) 
where p.name='computer desk'     
group by s.name                     -- aggregate by salesperson 
order by n desc limit 1;            -- order by descending sum, pick off top value 
+------+------+ 
| name | n    | 
+------+------+ 
| Sam  |    4 | 
+------+------+

如果必须检索那些没有GROUP BY的列,且与分组表达式没有严格的1:1的关系,然后要避免返回非分组列的任意值,你可以把这些列加入到group by ,或者把GROUP BY 放在一个子查询中,然后与其他列join这些结果,例如:

SELECT s.partID, s, thiscol, s.thatcol, anothercol, x.Suppliers 
FROM supparts s 
JOIN ( 
  SELECT partID,GROUP_CONCAT(supID ORDER BY supID) AS Suppliers  
  FROM supparts  
  GROUP BY partID 
) x USING(partID)

如果sql_mode中包含ONLY_FULL_GROUP_BY,对于一个查询,选择了非聚合列,且没有函数依赖于分组列,MySQL会返回一个错误。

注:如果想知道sql_mode变量的值 ,可以用以下语句查询:

mysql> show variables like'sql_mode';
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

results matching ""

    No results matching ""