MySQL在多个列上加入的每个组的最大值

时间:2019-02-22 23:00:38

标签: mysql max left-join grouping

我找到了许多其他类似查询的答案,但都不满足我的要求,因此就是问题。

首先,数据:

orderid    type    year    change
1111       1       2018    333
1111       2       2018    4652
1111       1       2019    3645
1111       3       2019    444
2222       1       2018    6451

在订单号,类型和年份列上有一个联合键。因此,对于某种类型,每个订单每年可以有一个条目。

现在,所需的结果(选项1):

orderid    type    year    change
1111       2       2018    4652
1111       1       2019    3645

我正在寻找的是每年给定订单的最大“更改”值。类型无关紧要。 “ 1111”是传递给查询的示例订单。

并且如果可以进一步改善第一个挑战,则理想情况下,我希望从上述答案中获得变更的总和。因此理想的结果应如下所示(选项2):

orderid    change
1111       8297

我还没有尝试得到第二个答案,从技术上讲,这应该是对结果进行附加查询以汇总返回的更改列的简便包装。但是,到目前为止,我为第一个问题(并添加-没有成功)尝试过的是:

SELECT t1.*
FROM table1 t1
   LEFT JOIN table1 t2
   ON t1.orderid = t2.orderid AND t1.year = t2.year AND t1.change > t2.change
WHERE t2.change IS NULL
AND t1.orderid = '1111'

此查询返回的结果并非完全是期望的结果,其中一个最大值是正确的,而另一个不是:

orderid    type    year    change
1111       1       2018    333
1111       1       2019    3645

是的。现在谁愿意保存我的星期五晚上?

总是很感谢帮助!

更新1: 我在上述所有内容中都包含sqlfiddle: SQLFiddle

2 个答案:

答案 0 :(得分:1)

您的SQLFiddle无法正常工作有两个原因。首先,也是最重要的是,您将change的值声明为VARCHAR而不是INT。结果,MySQL认为444> 3645。其次,JOIN条件应该是t1.change < t2.change,而不是t1.change > t2.change。请参见updated SQLFiddle,它会提供您想要的结果:

orderid     type    year    change
1111        2       2018    4652
1111        1       2019    3645

如果该字段必须保留VARCHAR,则需要将JOIN条件更改为

CAST(t1.change AS UNSIGNED) < CAST(t2.change AS UNSIGNED)

要获取更改的总和,只需将您的查询用作子查询,SUM更改和GROUP BY orderid

SELECT orderid, SUM(`change`) AS total_change
FROM (SELECT t1.*
      FROM table1 t1
      LEFT JOIN table1 t2
          ON t1.orderid = t2.orderid AND t1.year = t2.year AND t1.change < t2.change
      WHERE t2.change IS NULL AND t1.orderid = '1111') t
GROUP BY orderid

输出:

orderid     total_change
1111        8297

Demo on SQLFiddle

答案 1 :(得分:1)

尝试比较值时,您的问题是VARCHAR类型。

因此,比较时您需要CAST值,或者change your schema

 ALTER TABLE table1 MODIFY COLUMN `change` INT;

http://sqlfiddle.com/#!9/b2786a/6

SELECT t1.*
FROM table1 t1
LEFT JOIN table1 t2
ON t1.orderid = t2.orderid 
   AND t1.year = t2.year 
   AND CAST(t1.change  AS UNSIGNED)  < CAST(t2.change AS UNSIGNED)
WHERE t2.change IS NULL
AND t1.orderid = '1111';

SELECT t1.*
FROM table2 t1
LEFT JOIN table2 t2
ON t1.orderid = t2.orderid 
   AND t1.year = t2.year 
   AND t1.change < t2.change
WHERE t2.change IS NULL
AND t1.orderid = '1111'