使用SUM和GROUP BY从一列中选择MAX,而不使用子查询

时间:2017-10-03 11:24:59

标签: mysql sql

请考虑下表。

+----+------+--------+-------------+---------------------+
| id | user | amount | description |       paid_on       |
+----+------+--------+-------------+---------------------+
|  1 |    1 |    200 | wire        | 2017-09-01 15:45:52 |
|  2 |    2 |    200 | paypal      | 2017-09-09 05:05:05 |
|  3 |    3 |    150 | cash        | 2017-09-02 12:34:56 |
|  4 |    1 |     20 | wire        | 2017-01-09 01:23:45 |
+----+------+--------+-------------+---------------------+

我正在尝试获取每个用户的总付款以及该用户的最后付款日期。为此,我正在使用

    SELECT
        user,
        ROUND(SUM(amount),2) AS amount,
        date_format(paid_on, '%d.%m.%Y.') AS paid_on
    FROM
        (
            SELECT
                user,
                amount,
                paid_on
            FROM payments
            WHERE paid_on BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59'
            ORDER BY paid_on DESC
         ) tmppayments
    GROUP BY user

它按照我的预期工作,因为它返回了我的想法。但是,使用子查询似乎有点矫枉过正。是否可以使用简单的(r)查询执行此操作,而无需借助任何子查询?

7 个答案:

答案 0 :(得分:2)

这会吗?

SELECT
  user,
  ROUND(SUM(amount),2) AS amount,
  date_format(MAX(paid_on),'%d.%m.%Y.') AS paid_on
FROM
  payments
GROUP BY user

请注意,我遗漏了BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59'条件,因为您从未将其视为您想要的内容。

答案 1 :(得分:2)

使用MAX功能选择最新的paid_on日期。

<强>查询

select `user`,
round(sum(`amount`),2) as `amount`,
date_format(max(`paid_on`), '%d.%m.%Y.') as `paid_on`
from `payments`
where `paid_on` between '2017-09-01 00:00:00' and '2017-09-30 23:59:59'
group by `user`;

答案 2 :(得分:2)

然后不要使用子查询:

SELECT
    user,
    ROUND(SUM(amount),2) AS amount,
    MAX(date_format(paid_on, '%d.%m.%Y.')) AS max_paid_on
FROM payments
WHERE paid_on BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59'
GROUP BY user

虽然您应该知道子查询不一定会减慢您的查询速度,在这种情况下,它可能会赢得

答案 3 :(得分:2)

你试过这种方式吗?:

SELECT  user,
        ROUND(SUM(amount),2) AS amount,
        date_format(max(paid_on), '%d.%m.%Y.') AS paid_on
FROM payments
WHERE paid_on BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59'
GROUP BY user

答案 4 :(得分:2)

根本不需要子查询。而且,您还可以简化日期逻辑:

SELECT p.user, SUM(p.amount) as total_amount, MAX(p.paid_on) as max_paid_on
FROM payments p
WHERE p.paid_on >= '2017-09-01' AND p.paid_on <'2017-10-01' 
GROUP BY user
ORDER BY max_paid_on DESC;

注意:

  • 如果您愿意,可以格式化max_paid_on。我更喜欢ISO标准格式,YYYY-MM-DD,以及其他任何格式。
  • 我不建议将BETWEEN与日期或日期时间列一起使用。 Here是一篇很好的博客文章,解释了为什么(尽管它适用于SQL Server,它确实适用于所有数据库)。
  • 您的查询中存在逻辑错误。在外部selectpaid_on未被汇总,而且不在group by中。这几乎是任何其他数据库中的错误。
  • 你对子查询是正确的。 MySQL实现了子查询,这对于不需要子查询的查询来说是不必要的开销。

答案 5 :(得分:2)

SELECT
    p.user,
    ROUND(SUM(p.amount), 2) AS amount,
    date_format(MAX(p.paid_on), '%d.%m.%Y.') AS paid_on
FROM
    payments p
WHERE
    p.paid_on BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59'
GROUP BY
    p.user
ORDER BY
    p.paid_on DESC

答案 6 :(得分:1)

此处不必要地添加子查询。没有子查询的最佳方法是SELECT user, ROUND(SUM(amount),2) AS amount, date_format(max(paid_on), '%d.%m.%Y.') AS paid_on FROM payments WHERE paid_on BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59' GROUP BY user 希望能帮助到你。