Reputation: 2255
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?
Upvotes: 2
Views: 1781
Reputation: 324
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.
Upvotes: 1
Reputation: 11556
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`;
Upvotes: 2
Reputation: 353
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
Upvotes: 2
Reputation: 1271003
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:
max_paid_on
if you like. I much prefer the ISO standard format, YYYY-MM-DD, to any other.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).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.Upvotes: 2
Reputation: 5396
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
Upvotes: 2
Reputation: 40491
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
Upvotes: 2
Reputation: 16784
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.
Upvotes: 2