I'm having a challenge to get the monthly total sum of amount_tendered from both shop1 table and shop2 table, and the monthly total sum of payment_amount from payments table.
and if payments don't have a value for the month it should show zero.
shop1
--------------------------------------------------------
| trans_id | amount_tendered | trans_date |
--------------------------------------------------------
| 1 | 10.00 | 2020-09-03 06:09:55 |
| 2 | 15.00 | 2020-08-01 10:19:01 |
--------------------------------------------------------
shop2
--------------------------------------------------------
| trans_id | amount_tendered | trans_date |
--------------------------------------------------------
| 1 | 30.00 | 2020-09-01 16:09:55 |
| 2 | 15.00 | 2020-09-11 11:19:01 |
--------------------------------------------------------
Payments
------------------------------------------------------------
| payments_id | payment_amount | payment_date |
------------------------------------------------------------
| 1 | 100.00 | 2020-09-01 16:09:55 |
| 2 | 105.00 | 2020-09-11 11:19:01 |
------------------------------------------------------------
SELECT t1.yr, t1.mnth, ifnull(t2.total_trans,0), ifnull(t3.payments,0) FROM
(SELECT YEAR(trans_date) as yr,
MONTHNAME(trans_date) as mnth,
FROM shop1
GROUP BY YEAR(trans_date), MONTHNAME(trans_date)
ORDER BY YEAR(trans_date), MONTHNAME(trans_date)) as t1
LEFT JOIN (
SELECT(
(SUM(amount_tendered) FROM shop1 GROUP BY YEAR(trans_date), MONTHNAME(trans_date)+
(SUM(amount_tendered) FROM shop2 GROUP BY YEAR(trans_date), MONTHNAME(trans_date)
) as 'total_trans'
)as t2
LEFT JOIN (
SELECT SUM(payment_amount ) FROM transactions GROUP BY YEAR(payment_date), MONTHNAME(payment_date) as payments
)as t3
The expected result
------------------------------------------------------------
| yr | mnth | total_trans | payments |
------------------------------------------------------------
| 2020 | August | 15.00 | 0.00 |
| 2020 | September| 55.00 | 105.00 |
------------------------------------------------------------
Error : Syntax error near 'FROM transactions GROUP BY YEAR(transaction_date), MONTHNAME(transaction_date) ' at line 4
You would typically compute the monthly sum in two separate subqueries, and then join the results.
I am not a fan of having one table per shop: having several tables with the same columns usually indicates a design problem. Here, we use union all to collect data from both tables before aggregating.
select t.*, p.payments
from (
select year(trans_date) yr, monthname(trans_date) mnth, sum(amount_tendered) total_trans
from (
select trans_date, amount_tendered from shop1
union all
select trans_date, amount_tendered from shop2
) t
group by year(trans_date), monthname(trans_date)
) t
left join (
select year(payment_date) yr, monthname(payment_date) mnth, sum(payment_amount) payments
from payments
group by year(payment_date), monthname(payment_date)
) p on p.yr = t.yr and p.mnth = t.mnth
The left join avoids filtering out months that have no transactions.
Related
I have 3 tables councils, station_levy, market_levy, and the station table is joined to get councils in station_levy.
I need to get data by council sum the number of station_levy + market_levy and get the total amount tendered.
Tables are as follows
councils
---------------+----------+
| council_id | Name |
+--------------+----------+
| 1 | LSK |
---------------+----------+
| 2 | KBW |
---------------+----------+
station_levy
------------------+-------------+-----------------+
| station_levy_id | station_id | amount_tendered |
+-----------------+-------------+-----------------+
| 1 | 3 | 10.00 |
+-----------------+-------------+-----------------+
| 2 | 3 | 10.00 |
+-----------------+-------------+-----------------+
| 3 | 1 | 5.00 |
+-----------------+-------------+-----------------+
(station_id = 1 is found in the LSK council_id=1 And station_id = 3 is found in the KBW council_id=2)
market_levy
------------------+-------------+-----------------+
| market_levy_id | council_id | amount_tendered |
+-----------------+-------------+-----------------+
| 1 | 1 | 5.00 |
+-----------------+-------------+-----------------+
| 2 | 2 | 5.00 |
+-----------------+-------------+-----------------+
| 3 | 1 | 5.00 |
+-----------------+-------------+-----------------+
mysql
SELECT c.council_name, (COUNT(market_levy.market_levy_id)+ COUNT(st.station_levy_id )) count, SUM(amount_tendered) revenue
FROM councils c
JOIN (
(SELECT council_id, amount_tendered,market_levy_id FROM market_levy WHERE transaction_date >= CURDATE() )
UNION ALL
(SELECT station_levy_id , councils.council_id, amount_tendered
FROM station_levy st
JOIN stations ON stations.station_id = st.station_id
JOIN councils ON councils .council_id= stations .council_id
WHERE transaction_datetime >= CURDATE()
)) totalCouncilRevenue USING (council_id)
group by council_id, c.council_name ORDER BY SUM(amount_tendered) DESC
Expected result
------------------+-------------+-----------------+
| council_name | count | revenue |
+-----------------+-------------+-----------------+
| LSK | 3 | 15.00 |
+-----------------+-------------+-----------------+
| KBW | 3 | 25.00 |
+-----------------+-------------+-----------------+
You are confusing columns in your UNION ALL matching council_id with station_levy_id, amount_tendered with council_id, and market_levy_id with amount_tendered.
Then, in your main query you try to access market_levy.market_levy_id and st.station_levy_id, but these columns are not accessible, as you select from a subquery called totalCouncilRevenue, not from tables labelled market_levy and st there.
Your query fixed:
SELECT
c.council_name,
COUNT(*) AS transaction_count,
SUM(amount_tendered) AS revenue
FROM councils c
JOIN
(
SELECT council_id, amount_tendered
FROM market_levy
WHERE transaction_date >= CURDATE()
UNION ALL
SELECT s.council_id, st.amount_tendered
FROM station_levy st
JOIN stations s ON s.station_id = st.station_id
WHERE st.transaction_datetime >= CURDATE()
) totalCouncilRevenue USING (council_id)
GROUP BY council_id, c.council_name
ORDER BY SUM(amount_tendered) DESC;
I prefer aggregating before joining, though:
SELECT
c.council_name,
COALESCE(t1.cnt, 0) + COALESCE(t2.cnt, 0) AS transaction_count,
COALESCE(t1.total, 0) + COALESCE(t2.total, 0) AS revenue
FROM councils c
LEFT JOIN
(
SELECT council_id, SUM(amount_tendered) as total, COUNT(*) as cnt
FROM market_levy
WHERE transaction_date >= CURDATE()
GROUP BY council_id
) t1 USING (council_id)
LEFT JOIN
(
SELECT s.council_id, SUM(st.amount_tendered) as total, COUNT(*) as cnt
FROM station_levy st
JOIN stations s ON s.station_id = st.station_id
WHERE st.transaction_datetime >= CURDATE()
GROUP BY s.council_id
) t2 USING (council_id)
ORDER BY revenue DESC;
Such queries are usually less prone to errors and are sometimes faster, because they may be able to use indexes more efficiently.
With reference to this question (How to get the sum in a joined table when using group by - getting wrong results) I have two tables orders and order_items. I need to group the results by days. But I also need to get the sum of energy_used for each day from another table. When I try that using a join, I get wrong order_sum for each day (they are not being summed up). Not sure what I am doing wrong.
I would like to get for each day
the sum of order_items.energy_used for all orders created that day
the sum of orders.order_sum for all orders created that day
the created_at and order_sum that correspond to the latest order created on that day
Here is my orders table
+----+-----------+---------+---------------------+
| id | order_sum | user_id | created_at |
+----+-----------+---------+---------------------+
| 1 | 25.13 | 7 | 2020-01-25 09:13:00 |
| 2 | 10.00 | 7 | 2020-01-25 15:23:00 |
| 3 | 14.00 | 5 | 2020-01-26 10:14:00 |
| 4 | 35.00 | 1 | 2020-01-27 11:13:00 |
+----+-----------+---------+---------------------+
And here is my order_items table
+----+----------+-------------+---------------------+
| id | order_id | energy_used | created_at |
+----+----------+-------------+---------------------+
| 1 | 1 | 65 | 2020-01-25 09:13:00 |
| 2 | 1 | 12 | 2020-01-25 09:13:00 |
| 3 | 2 | 70 | 2020-01-26 10:14:00 |
| 4 | 2 | 5 | 2020-01-26 10:14:00 |
| 5 | 3 | 0 | 2020-01-27 11:13:00 |
+----+----------+-------------+---------------------+
And this is the desired result that I am trying to achieve
+---------------+-----------------+-------------------+---------------------+----------------+
| date_of_month | total_order_sum | total_energy_used | last_order_date | last_order_sum |
+---------------+-----------------+-------------------+---------------------+----------------+
| 2020-01-25 | 35.13 | 77 | 2020-01-25 09:13:00 | 25.13 |
| 2020-01-26 | 14.00 | 75 | 2020-01-26 10:14:00 | 14.00 |
| 2020-01-27 | 35.00 | 0 | 2020-01-27 11:13:00 | 35.00 |
+---------------+-----------------+-------------------+---------------------+----------------+
And here is the query that I have tried but I'm getting wrong results, the order_sum is not being calculated correctly. It is showing the same as last_order_sum
select
date(o.created_at) date_of_month,
i.total_energy_used,
o.created_at last_order_date,
o.order_sum last_order_sum,
sum(order_sum) as total_order_sum
from orders o
inner join (
select date(o1.created_at) date_of_month, sum(i1.energy_used) total_energy_used
from orders o1
inner join order_items i1 on o1.id = i1.order_id
group by date(o1.created_at)
) i on i.date_of_month = date(o.created_at)
where o.created_at = (
select max(o1.created_at)
from orders o1
where date(o1.created_at) = date(o.created_at)
)
Here is a fiddle:
https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=92b8cc2920ad9f7a7cdd56bded5a3bf2
Always join tables together on their relationships (in this case orders.id with order_items.order_id) and then group. to avoid duplicating order_sums for multiple order_items when joining, first group order_items by order_id.
select
date(o.created_at) date_of_month,
sum(i.total_energy_used),
max(o.created_at),
sum(order_sum) as total_order_sum
from orders o
inner join (
select order_id, sum(total_energy_used) total_energy_used
from order_items i
group by order_id
) i on o.id = i.order_id
group by date(o.created_at)
from this point onwards you can do a join again on orders with max(o.created_at) to get the order_sum of the last order.
moral of the story: keep an eye on your granularity.
Your problem is that you are selecting from orders, where you actually want an aggregate of orders by date. So select from two aggregtating subqueries that you join. Only problem is last_order_sum, which we can select in a further subquery, once we know the last order date.
select
order_date,
o.total_order_sum,
oi.total_energy_used,
o.last_order_date,
(
select order_sum
from orders last_order
where lastorder.created_at = o.last_order_date
) as last_order_sum
from
(
select
date(created_at) as order_date,
sum(order_sum) as total_order_sum,
max(created_date) as last_order_date
from orders
group by date(created_at)
) o
inner join
(
select
date(created_at) as order_date,
sum(energy_used) as total_energy_used
from order_items
group by date(created_at)
) oi using(order_date)
order by order_date;
What you are asking and what you show us in output are not correlated. Assuming that it is a typo:
select so.dtDay as date_of_month, so.order_sum as total_order_sum,
eu.energy_used as total_energy_used,
o.created_at as last_order_date,
o.order_sum as last_order_sum
from (
select left(created_at,10) as dtDay, sum(order_sum) as order_sum, max(id) as last_insert_id
from orders
group by left(created_at,10)
order by created_at
) so
inner join orders o on o.id = so.last_insert_id
left join (select left(created_at,10) as dtDay, sum(energy_used) as energy_used
from order_items
group by left(created_at,10)) eu on so.dtDay = eu.dtDay;
DBFiddle
Sample Data
id | order_id | instalment_num | date_due
---------------------------------------------------------
1 | 10000 | 1 | 2010-07-09 00:00:00
2 | 10000 | 1 | 2010-09-06 11:39:56
3 | 10001 | 1 | 2014-04-25 15:46:52
4 | 10002 | 1 | 2010-01-11 00:00:00
5 | 10003 | 1 | 2010-01-04 00:00:00
6 | 10003 | 1 | 2016-05-31 00:00:00
7 | 10003 | 1 | 2010-01-08 00:00:00
8 | 10003 | 1 | 2010-01-06 09:06:26
9 | 10004 | 1 | 2010-01-11 11:25:07
10 | 10004 | 1 | 2010-01-12 07:06:42
Desired Result
id | order_id | instalment_num | date_due
---------------------------------------------------------
1 | 10000 | 1 | 2010-07-09 00:00:00
2 | 10000 | 2 | 2010-09-06 11:39:56
3 | 10001 | 1 | 2014-04-25 15:46:52
4 | 10002 | 1 | 2010-01-11 00:00:00
5 | 10003 | 1 | 2010-01-04 00:00:00
8 | 10003 | 2 | 2010-01-06 09:06:26
7 | 10003 | 3 | 2010-01-08 00:00:00
6 | 10003 | 4 | 2016-05-31 00:00:00
9 | 10004 | 1 | 2010-01-11 11:25:07
10 | 10004 | 2 | 2010-01-12 07:06:42
As you can see, I have an instalment_num column which should show the number/index of each row belonging to the order_id, determined by the date_due ASC, id ASC order.
How can I update the instalment_num column like this?
Additional Notes
The date_due column is not unique, and there may be many ids or order_ids with the exact same timestamp.
If the timestamp is the same for two rows belonging to the same order_id, it should order them by id as a fallback.
I require a query which will update this column.
This is how I would do it:
SELECT a.id,
a.order_id,
COUNT(b.id)+1 AS instalment_num,
a.date_due
FROM sample_data a
LEFT JOIN sample_data b ON a.order_id=b.order_id AND (a.date_due>b.date_due OR (a.date_due=b.date_due AND a.id>b.id))
GROUP BY a.id, a.order_id, a.date_due
ORDER BY a.order_id, a.date_due, a.id
UPDATE version attempt:
UPDATE sample_data
LEFT JOIN (SELECT a.id,
COUNT(b.id)+1 AS instalment_num
FROM sample_data a
JOIN sample_data b ON a.order_id=b.order_id AND (a.date_due>b.date_due OR (a.date_due=b.date_due AND a.id>b.id))
GROUP BY a.id) c ON c.id=sample_data.id
SET sample_data.instalment_num=c.instalment_num
For the numbering to begin with 1:
UPDATE sample_data
LEFT JOIN (SELECT a.id,
COUNT(b.id) AS instalment_num
FROM sample_data a
JOIN sample_data b ON a.order_id = b.order_id AND (a.date_due > b.date_due OR (a.date_due=b.date_due AND a.id + 1 > b.id))
GROUP BY a.id) c ON c.id = sample_data.id
SET sample_data.instalment_num = c.instalment_num
You are trying to achieve what ROW_NUMBER with a partition would do using something like SQL Server or Oracle. You can simulate this with an approriate query:
SELECT t.id, t.order_id,
(
SELECT 1 + COUNT(*)
FROM sampleData
WHERE (date_due < t.date_due OR (date_due = t.date_due AND id < t.id)) AND
order_id = t.order_id
) AS instalment_num,
t.date_due
FROM sampleData t
ORDER BY t.order_id, t.date_due
This query will order the instalment_num by due_date in ascending order. And in the case of a tie in due_date, it will order by the id in ascending order.
Follow the link below for a demo:
SQLFiddle
select
sub.order_id, sub.date_due,
#group_rn:= case
when #group_order_id=sub.order_id then #group_rn:=#group_rn:+1
else 1
end as instalment_num,
#group_order_id:=sub.order_id
FROM (select #group_rn:=0, group_order_id=0) init,
(select *
from the_table
order by order_id, date_due) sub
So i have table cont_selling
---------------------------------
cont_selling_id | date |
---------------------------------
1 | 2015-05-24 |
2 | 2015-06-06 |
---------------------------------
table 02 cont_sold
----------------------------------------------------
cont_sold_id | cont_selling_id | price |
---------------------------------------------------
1 | 1 | 10 |
2 | 1 | 10 |
3 | 1 | 30 |
4 | 2 | 20 |
5 | 2 | 10 |
--------------------------------------------------
and table 03 payment
----------------------------------------------
payment_id | cont_selling_id | paid |
-----------------------------------------------
1 | 1 | 10 |
2 | 2 | 10 |
3 | 1 | 20 |
4 | 1 | 10 |
5 | 2 | 10 |
-----------------------------------------------
now i need to SELECT table based on
now i want to merge all these three tables based on cont_selling table cont_selling_id column
and want to SUM cont_sold table price column and payment table paid column
this is what i want to do
expecting output
---------------------------------------------
cont_selling_id | price | paid |
---------------------------------------------
1 | 50 | 40 |
2 | 30 | 20 |
---------------------------------------------
so i tried like this in mysql query but it give wrong sum result
SELECT
SUM(Z.price) as total,
SUM(P.amount) as paid
FROM cont_selling S
LEFT JOIN cont_sold Z
ON S.cont_selling_id = Z.cont_selling_id
LEFT JOIN payment P
ON S.cont_selling_id = P.cont_selling_id
GROUP BY S.cont_selling_id
for this above query i m getting output like this
---------------------------------------------
cont_selling_id | price | paid |
---------------------------------------------
1 | 150 | 40 |
2 | 60 | 120 |
---------------------------------------------
Here how you can do it using the aggegare part into inner queries and then join
select
cs.cont_selling_id,
price,
paid
from cont_selling cs
left join(
select sum(price) as price , cont_selling_id from cont_sold
group by cont_selling_id
)x on x.cont_selling_id = cs.cont_selling_id,
left join(
select sum(paid) as paid , cont_selling_id from payment
group by cont_selling_id
)y
on y.cont_selling_id = cs.cont_selling_id;
You should make two different queries with SUM and then combine them to get the desired result:
SELECT T1.cont_selling_id,T1.price,T2.paid
FROM
(SELECT c.cont_selling_id,SUM(cs.price) as price
FROM cont_selling c LEFT JOIN
cont_sold cs ON c.cont_selling_id=cs.cont_selling_id
GROUP BY c.cont_selling_id) as T1 JOIN
(SELECT c.cont_selling_id,SUM(p.paid) as paid
FROM cont_selling c LEFT JOIN
payment p ON p.cont_selling_id=c.cont_selling_id
GROUP BY c.cont_selling_id) as T2 ON T1.cont_selling_id=T2.cont_selling_id
Result:
cont_selling_id price paid
----------------------------
1 50 40
2 30 20
Sample result in SQL Fiddle.
This untested query should work:
with a as(select cont_selling_id , sum(price) as totalprice from cont_sold group by cont_selling_id),
with a as(select cont_selling_id , sum(paid) as totalpaid from payment group by cont_selling_id),
select c.cont_selling_id , totalprice, totalpaid from cont_selling c left join a.count_selling_id = c.count_selling_id
left join b.count_selling_id = c.count_selling_id
You have to create temporary tables, because there is no dependency between your table for price and paid.
This is a small snippet of my table, which currently contains ~10,000,000 rows
+---------+---------------------+-----------+----------------+
| card_id | date | avg_price | foil_avg_price |
+---------+---------------------+-----------+----------------+
| 10000 | 2014-06-28 09:05:56 | 5.02 | 10.22 |
| 20000 | 2014-06-28 09:05:54 | 14.58 | 25.10 |
| 10000 | 2014-06-29 09:05:56 | 0.00 | 19.62 |
| 20000 | 2014-06-29 09:05:54 | 14.58 | 0.00 |
| 10000 | 2014-07-01 09:05:56 | 0.00 | 19.62 |
| 20000 | 2014-07-01 09:05:54 | 0.00 | 25.10 |
+---------+---------------------+-----------+----------------+
It is a price history for cards, including what the avg_price and what the foil_avg_price was for each day or so.
I'd like to select, for a group of card id's the most recent date when the foil_avg_price was > 0, what that price was, and the most recent date that the avg_price was > 0, and what that price was. My resulting data set for the above would look something like this:
+---------+---------------------+-----------+---------------------+----------------+
| card_id | avg_date | avg_price | foil_date | foil_avg_price |
+---------+---------------------+-----------+---------------------+----------------+
| 10000 | 2014-06-28 09:05:56 | 5.02 | 2014-07-01 09:05:54 | 19.62 |
| 20000 | 2014-06-29 09:05:54 | 14.58 | 2014-07-01 09:05:54 | 25.10 |
+---------+---------------------+-----------+---------------------+----------------+
I'm sure that this involves an INNER JOIN on the same table but I can't quite get my head around it. Any help would be much appreciated.
Three steps:
Find last price date
Find last foil price date
resolve prices on these dates
So,
SELECT dates.*, price.avg_price, foilprice.foil_avg_price
FROM (
SELECT
card_id,
MAX(IF(avg_price>0, `date`, '0001-01-01')) AS avg_date,
MAX(IF(foil_avg_price>0, `date`, '0001-01-01')) AS foil_avg_date
FROM card_price
GROUP BY card_id
) AS dates
INNER JOIN card_price AS price
ON dates.card_id=price.`date`
INNER JOIN card_price AS foilprice
ON dates.card_id=foilprice.`date`
Try this query
SELECT A.card_id,max(date),MAX(avg_price), (SELECT MAX(date) FROM test WHERE card_id = A.card_id AND foil_avg_price = MAX(A.foil_avg_price)) AS date,MAX(foil_avg_price) FROM test A
GROUP BY A.card_id
How about if you had 20,000,000 rows...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(card_id INT NOT NULL
,date DATETIME NOT NULL
,price_type VARCHAR(20) NOT NULL
,price_value DECIMAL(5,2) NOT NULL
,PRIMARY KEY(card_id,date,price_type)
);
INSERT INTO my_table VALUES
(10000,'2014-06-28 09:05:56','avg_price',5.02),
(20000,'2014-06-28 09:05:54','avg_price',14.58),
(10000,'2014-06-29 09:05:56','avg_price',0.00),
(20000,'2014-06-29 09:05:54','avg_price',14.58),
(10000,'2014-07-01 09:05:56','avg_price',0.00),
(20000,'2014-07-01 09:05:54','avg_price',0.00),
(10000,'2014-06-28 09:05:56','foil_avg_price',10.22),
(20000,'2014-06-28 09:05:54','foil_avg_price',25.10),
(10000,'2014-06-29 09:05:56','foil_avg_price',19.62),
(20000,'2014-06-29 09:05:54','foil_avg_price',0.00),
(10000,'2014-07-01 09:05:56','foil_avg_price',19.62),
(20000,'2014-07-01 09:05:54','foil_avg_price',25.10);
SELECT x.*
FROM my_table x
JOIN
( SELECT card_id,price_type,MAX(date) max_date FROM my_table WHERE price_value > 0 GROUP BY card_id,price_type) y
ON y.card_id = x.card_id
AND y.price_type = x.price_type
AND y.max_date = x.date;
+---------+---------------------+----------------+-------------+
| card_id | date | price_type | price_value |
+---------+---------------------+----------------+-------------+
| 10000 | 2014-06-28 09:05:56 | avg_price | 5.02 |
| 10000 | 2014-07-01 09:05:56 | foil_avg_price | 19.62 |
| 20000 | 2014-06-29 09:05:54 | avg_price | 14.58 |
| 20000 | 2014-07-01 09:05:54 | foil_avg_price | 25.10 |
+---------+---------------------+----------------+-------------+
Try this:
SELECT a.card_id, a.avg_date, a.avg_price, b.foil_date, b.foil_avg_price
FROM (SELECT c.card_id, c.date AS avg_date, c.avg_price
FROM cards c
INNER JOIN (SELECT c.card_id, MAX(IF(c.avg_price > 0, c.date, NULL)) avg_date
FROM cards c GROUP BY c.card_id
) a ON c.card_id = a.card_id AND c.date = a.avg_date
) AS a
LEFT JOIN (SELECT c.card_id, c.date AS foil_date, c.foil_avg_price
FROM cards c
INNER JOIN (SELECT c.card_id, MAX(IF(c.foil_avg_price > 0, c.date, NULL)) foil_date
FROM cards c GROUP BY c.card_id
) a ON c.card_id = a.card_id AND c.date = a.foil_date
) AS b ON a.card_id = b.card_id ;
OR
SELECT a.card_id, a.avg_date, a.avg_price, b.foil_date, b.foil_avg_price
FROM (SELECT *
FROM (SELECT c.card_id, c.date, c.avg_price
FROM cards c WHERE c.avg_price > 0
ORDER BY c.date DESC
) AS A
GROUP BY A.date
) AS a
LEFT JOIN ( SELECT *
FROM (SELECT c.card_id, c.date, c.foil_avg_price
FROM cards c WHERE c.foil_avg_price > 0
ORDER BY c.date DESC
) AS B
GROUP BY B.date
) AS b ON a.card_id = b.card_id;