一列中最大,另一列中最小

时间:2012-07-13 01:59:03

标签: mysql sql aggregate-functions

例如,如果列A和列B具有值:

+---+---+
| A | B |
+---+---+
| 2 | 1 |
| 5 | 1 | 
| 6 | 1 |
| 1 | 2 |
| 5 | 2 |
| 0 | 2 |
| 2 | 3 |
| 7 | 3 |
| 4 | 3 |
| 5 | 4 |
+---+---+

从B的每一组中,我想从A中获得最高的数字。但是,我不想包括B中的数字较高但A值小于前一个的结果。我知道这在单词中没有意义,但这就是我想要的最终结果:

+---+---+
| A | B |
+---+---+
| 6 | 1 |
| 7 | 3 |
+---+---+

到目前为止,我有类似“选择max(a),b来自table1 group by b”的内容,但这并没有省略B更高但最大A更小的那些。我知道我可以在PHP中仔细阅读该查询的结果,并删除A值小于之前的A值的那些,但是如果可能的话我想把它全部放在mysql查询中。

3 个答案:

答案 0 :(得分:5)

此技术将表与其自身的聚合版本连接,但是连接偏移一个,因此每一行都与前一个B的MAX(A)值相关联。然后它匹配当前A大于其中任何一个的行,如果它没有找到任何行,则它不包括该行。然后我们汇总最终选择以获得您所追求的结果。

SELECT 
       MAX(source_row.A) as A, 
       source_row.B
  FROM ab as source_row
  LEFT JOIN (SELECT MAX(A) as A, B FROM ab GROUP BY B) AS one_back 
    ON one_back.B = source_row.B-1 
 WHERE (one_back.A IS NULL) 
    OR one_back.A < source_row.A
 GROUP BY B

我测试了这个: - )

编辑:额外见解

我想分享一下我如何提出这些解决方案;因为我认为人们开始“集中思考”很重要......这是我读过的有关JOINS的最佳建议,你需要设想你的查询正在使用的中间“集合”。为了说明这一点,这里是中间“集合”的表示,它是该查询的关键部分;它是表格,因为它存在“加入”其自身的聚合版本。

+------+------+------------+------------+
| A    | B    | one_back.B | one_back.A |
+------+------+------------+------------+
|    2 |    1 |       NULL |       NULL |
|    5 |    1 |       NULL |       NULL |
|    6 |    1 |       NULL |       NULL |
|    1 |    2 |          1 |          6 |
|    5 |    2 |          1 |          6 |
|    0 |    2 |          1 |          6 |
|    2 |    3 |          2 |          5 |
|    7 |    3 |          2 |          5 |
|    4 |    3 |          2 |          5 |
|    5 |    4 |          3 |          7 |
+------+------+------------+------------+

然后,实际的集合在内存中创建(完整的连接版本永远不会完全在内存中,因为MySQL一知道它们就不会消除行“切割”:

+------+------+------------+------------+
| A    | B    | one_back.B | one_back.A |
+------+------+------------+------------+
|    2 |    1 |       NULL |       NULL |
|    5 |    1 |       NULL |       NULL |
|    6 |    1 |       NULL |       NULL |
|    7 |    3 |          2 |          5 |
+------+------+------------+------------+

然后,当然,它会将结果汇总到最终形式,只从原始行中选择A和B.

答案 1 :(得分:1)

更简单的解决方案是使用变量存储前一行的a值,并在每次迭代时进行比较。这也解释了b列中可能存在间隙的情况,其中数字并非完全按顺序排列:

SELECT @val:=a.a AS a, a.b
FROM
(
  SELECT MAX(a) AS a, b
  FROM tbl
  GROUP BY b
) a
WHERE a.a > IFNULL(@val,-1)

答案 2 :(得分:0)

Select Z.a, Z.b from
(select a, b, rank() over (order by b) as ranker from (select max(a) a, b  from table1 group by b) Y) Z left join
(select a, b, rank() over (order by b) as ranker from (select max(a) a, b  from table1 group by b) Y1) Z1
on Z.ranker = Z1.ranker + 1
where Z.a > isnull(Z1.a, -100000)