mysql - 如何查询按2个属性分组的最大值?

时间:2015-08-17 16:07:43

标签: mysql

所以我有一个表格,其中包含构成主键的2个属性base_idsub_id。该表包含值列表和值有效的日期,如下所示:

 base_id | sub_id | validity_start_date | value
---------+--------+---------------------+-------
 1       | 1      | 1970-01-01          | 50
 1       | 1      | 2000-01-01          | 55
 1       | 2      | 1970-02-02          | 50
 1       | 2      | 2000-02-02          | 55
 1       | 3      | 1970-03-03          | 50
 1       | 3      | 2000-03-03          | 55
 1       | 4      | 1970-04-04          | 50
 1       | 5      | 2015-05-05          | 66
 1       | 5      | 2015-06-06          | 70
 2       | 4      | 1970-01-01          | 80
 2       | 4      | 2015-01-01          | 75

我的目标是为唯一的主键找到最新的有效valuevalidity_start_date,如下所示:

 base_id | sub_id | validity_start_date | value
---------+--------+---------------------+-------   
 1       | 1      | 2000-01-01          | 55
 1       | 2      | 2000-02-02          | 55
 1       | 3      | 2000-03-03          | 55
 1       | 4      | 1970-04-04          | 50
 1       | 5      | 2015-06-06          | 70
 2       | 4      | 2015-01-01          | 75

为了帮助您,创建代码:

CREATE TABLE `rikai_test` (
  `base_id` int(10) unsigned NOT NULL,
  `sub_id` int(10) unsigned NOT NULL,
  `validity_start_date` date NOT NULL,
  `value` tinyint(3) unsigned DEFAULT NULL,
  PRIMARY KEY (`base_id`,`sub_id`,`validity_start_date`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `rikai_test` VALUES (1,1,'1970-01-01',50),(1,1,'2000-01-01',55),(1,2,'1970-02-02',50),(1,2,'2000-02-02',55),(1,3,'1970-03-03',50),(1,3,'2000-03-03',55),(1,4,'1970-04-04',50),(1,5,'2015-05-05',66),(1,5,'2015-06-06',70),(2,4,'1970-01-01',80),(2,4,'2015-01-01',75);

base_idsub_id进行分组或获得绝对最大值没有问题,但我无法将这些组合起来以获得分组的最大值。

3 个答案:

答案 0 :(得分:2)

此问题的常见解决方案是使用派生表查找每个组的最大值,并在连接中使用该表,如下所示:

select r.* 
from rikai_test r
join (
    select base_id, sub_id, max(validity_start_date) max_date 
    from rikai_test
    group by base_id, sub_id
) a on r.base_id = a.base_id 
   and r.sub_id = a.sub_id 
   and r.validity_start_date = a.max_date
order by r.base_id, r.sub_id;

结果将是:

base_id sub_id  validity_start_date value
1       1       2000-01-01          55
1       2       2000-02-02          55
1       3       2000-03-03          55
1       4       1970-04-04          50
1       5       2015-06-06          70
2       4       2015-01-01          75

Sample SQL Fiddle

答案 1 :(得分:2)

您可以使用左连接where null或者使用group-concat-trick来执行此操作。

第一个是“向我展示那些没有继承者使用相同的base_id,sub_id组合”的数据,这意味着“显示数据不存在更大日期的人”。

select d1.* 
from rikai_test d1
left join rikai_test d_not 
     on d1.base_id = d_not.base_id 
     and d1.sub_id = d_not.sub_id 
     and d1.validity_start_date < d_not.validity_start_date
where d_not.base_id is null

当然需要一个非空列(你有)。当然,如果您索引base_id,sub_id并且在一个组合中没有太多值,那么它最有效。使用where not exists (select ...)甚至可以改善它。

另一个是[正确]类型“给我每组最大的日期,但只是让这个约会带来它的亲戚到党”。所以我们将这个日期和实际值绑定在一起,让mysql最大化这个(因此排序数据必须在concat'ed对的开始处),当两者都达到最大值时,我们可以拆分它们。

 select base_id, sub_id, substring(constring, 1, 10) as start_date, substring(constring, 11, length(constring)
 from (select base_id, sub_id, max(concat(validity_start_date, value)) as constring group by base_id, sub_id ORDER BY constring) as innerselect

即使是更大的结果也应该非常快。

答案 2 :(得分:-2)

select * from rikai_test
where validity_start_date in
(select max(validity_start_date)
from rikai_test
group by base_id, sub_id)

SQL Fiidle