简体   繁体   中英

SELECT MAX from one column with SUM and GROUP BY for another, without subqueries

Consider the following table.

+----+------+--------+-------------+---------------------+
| 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 |
+----+------+--------+-------------+---------------------+

I'm trying to get the total payments for each user, and the last payment date for that same user. For this, I'm using

    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

It works as I expect it to, as it returns what I had in mind. However, using a subquery seems like an overkill. Is it possible to do this with a simple(r) query, without resorting to any subqueries?

Would this do?

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

Note that I left out the BETWEEN '2017-09-01 00:00:00' AND '2017-09-30 23:59:59' condition because you never mentioned it as something you wanted.

Use MAX function to select the latest paid_on date.

Query

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`;

Then just don't use a subquery :

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

Though you should know that a sub query won't necessarily slow down your query, and in this case it probably won't

Have you tried this way?:

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

You don't need the subquery at all. And, you can also simplify the date logic:

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;

Notes:

  • You can format max_paid_on if you like. I much prefer the ISO standard format, YYYY-MM-DD, to any other.
  • I don't recommend using BETWEEN with dates or date time columns. Here is a good blog post explaining why (although it is for SQL Server, it really applies to all databases).
  • Your query has a logical error in it. In the outer select , paid_on is not being aggregated and it is not in the group by . This would be an error in almost any other database.
  • You are right about the subquery. MySQL materializes subqueries, which is unnecessary overhead for queries that do not require the subqueries.
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

The subquery is unnecessarily added here. The best way to do it without the subquery is 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 Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM