获取组

时间:2016-03-19 13:12:23

标签: mysql join group-by

MySQL中,我尝试根据字段对表进行分组,但在每个组中输出某些字段的总和和最后一个值。对于每个问题,我都有解决方案,但两者都没有。

通过一个例子来解释会更容易。假设这是我们拥有的数据:

CREATE TABLE IF NOT EXISTS `trades` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `trader` int(11) NOT NULL,
  `volume` int(11) NOT NULL,
  `cash` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

INSERT INTO `trades` (`id`, `trader`, `volume`, `cash`) VALUES
(1, 1, 5, 0),
(2, 1, 7, 5),
(3, 1, 4, 2),
(4, 2, 10, 10);

所以我们的表格如下:

+----+--------+--------+------+
| id | trader | volume | cash |
+----+--------+--------+------+
|  1 |      1 |      5 |    0 |
|  2 |      1 |      7 |    5 |
|  3 |      1 |      4 |    2 |
|  4 |      2 |     10 |   10 |
+----+--------+--------+------+

现在,为了按trader分组并获得卷的总和,我们执行:

mysql> select trader, sum(volume) from trades group by trader;                                                                                                 
+--------+-------------+
| trader | sum(volume) |
+--------+-------------+
|      1 |          16 |
|      2 |          10 |
+--------+-------------+

这很容易。现在,为了获得每个组中的“最后”现金值,其中“最后”在这里我的意思是“最大的id”(但一般来说,这可以使用任何其他字段进行排序),I可以使用following clever idea(另请参阅here):

mysql> select t1.trader, t1.cash
    -> from trades t1 left join trades t2
    -> on t1.trader = t2.trader and t1.id < t2.id
    -> where t2.id is null;                            
+--------+------+
| trader | cash |
+--------+------+
|      1 |    2 |
|      2 |   10 |
+--------+------+

但是我如何结合这些解决方案,或者找到不同的解决方案,以获得看起来或多或少的结果如下:

+--------+--------+------+
| trader | volume | cash |
+--------+--------+------+
|      1 |     16 |    2 |
|      2 |     10 |   10 |
+--------+--------+------+

重要说明:我不想使用非健壮的解决方案,但在ONLY_FULL_GROUP_BY is enabled时失败。

另一个注意事项:我希望能够获得多个字段的“最后”值,但是对于单个排序这样做应该没问题。

2 个答案:

答案 0 :(得分:1)

在MySQL中基本上有三种方法:

  • 使用变量和聚合。
  • 使用连接和聚合。
  • 使用substring_index() / group_concat()技巧。

其中最后一项有一定的局限性。它将所有值转换为字符串。并且作为字符串的中间值的数量受参数group_concat_maxlen(可以更改)的限制。但是,当您已经进行聚合时,它是最简单的:

select trader, sum(volume),
       substring_index(group_concat(cash order by id desc), ',', 1) as last_cash
from trades
group by trader;

使用join的方法如下:

select t.trader, sum(t.volume),
       max(case when t.id = tt.maxid then cash end) as last_cash
from trades t left join
     (select trader, max(id) as maxid
      from trades t
      group by trader
     ) tt
     on t.trader = tt.trader
group by t.trader;

答案 1 :(得分:1)

您可以使用子查询查找每个交易者的总和和最大ID,然后加入表本身以获得现金值;

SELECT t1.trader, t2.volume, t1.cash
FROM trades t1
JOIN (
  SELECT trader, MAX(id) maxid, SUM(volume) volume FROM trades GROUP BY trader) t2
ON t1.id = t2.maxid

An SQLfiddle to test with