Reputation: 6959
I have the following table called table
:
| id | id_a | id_b | date | day_part |
===============================================
32043 | 0 | 0 | 2015-12-03 | A |
31933 | 0 | 31933 | 2015-12-03 | A |
31908 | 0 | 0 | 2015-12-03 | A |
31384 | 0 | 31384 | 2015-11-30 | M |
31335 | 0 | 0 | 2015-11-30 | M |
31303 | 0 | 31303 | 2015-11-30 | M |
31302 | 0 | 0 | 2015-11-30 | M |
31300 | 0 | 0 | 2015-11-30 | M |
31223 | 0 | 0 | 2015-12-03 | A |
31221 | 0 | 31221 | 2015-11-30 | M |
32037 | 0 | 32037 | 2015-12-03 | A |
31301 | 31301| 0 | 2015-11-30 | M |
31901 | 31301| 0 | 2015-11-30 | M |
id
is a unique id, day_part
refers to the part of the day ('A' means 'afternoon', 'M' means 'morning').
Lets say I have a range of dates between 2015-11-30
and 2015-12-06
.
For each day I need to find the COUNT
of the id
fields for each day_part
:
| date | M_ids_count | A_ids_count |
=========================================
2015-11-30 | 8 | 0
2015-12-03 | 0 | 5
I can easily do it with:
SELECT
date,
SUM(CASE WHEN day_part = 'M' THEN 1 ELSE 0 END) AS M_ids_count,
SUM(CASE WHEN day_part = 'A' THEN 1 ELSE 0 END) AS A_ids_count
FROM table
WHERE date BETWEEN '2015-11-30' AND '2015-12-06'
AND day_part IN ("M", "A")
GROUP BY date;
The tricky part is now:
I need to return the following result:
| date | M_ids_count | A_ids_count | M_trips_count | A_trips_count |
=========================================================================
2015-11-30 | 8 | 0 | 7 | 0
2015-12-03 | 0 | 5 | 0 | 5
We already now how to compute M_ids_count
and A_ids_count
.
M_trips_count
related to that nth date
and that nth day_part
and it's computed in the following way:
Condition 1: If I have the same id_a
for the same date
and day_part
, I need to sum 1
(i.e. the group counts one for me here);
Condition 2: If I id_a
is 0
and I have the same id_b
, I need to sum 1
(of course, e.g. if I have id_a
= 0 and three different id_b
, I need to sum 3
);
Condition 3: Otherwise, if id_a
and id_b
are 0
, I need to sum the COUNT
of the records;
The same goes for A_trips_count
and A_trips_count
but it is related to that date
in the afternoon day_part
.
So in our case, if you look at the table
you will see two fields with id_a = 31301
(having id
31301 and 31901) with the same date
and day_part
. This will count 1
as it meets the requirements of Condition 1
.
This 1
should then be added to the COUNT
of the records that meet Condition 2
for the same date
and day_part
: they are 3
(with id
s 31384, 31303, 31221). Here we have a total of 4
.
This 4
should then be added to the COUNT
of the records that meet Condition 3
for the same date
and day_part
: they are 3
(id
s -> 31335, 31302 and 31300).
Hence we get 7
which is the value for M_trips_count
for the day 2015-11-30
and the M
day_part
(i.e. the morning). The same computation should go for the A_trips_count
for the same date
but it's related to the afternoon.
Then the same should go for the other dates
in the range between 2015-11-30
and 2015-12-06
(in our case just for the date
2015-12-03
cause there aren't other dates). Same computation for M_trips_count
and A_trips_count
as for 2015-11-30
.
Now, can/how can I do it using just one SQL query?
The result I need is (the same as above):
| date | M_ids_count | A_ids_count | M_trips_count | A_trips_count |
=========================================================================
2015-11-30 | 8 | 0 | 7 | 0
2015-12-03 | 0 | 5 | 0 | 5
Thanks for the attention!
Upvotes: 0
Views: 31
Reputation: 998
Try the below code mostly will work.
SELECT t.dp AS date_part,
SUM(t.M_ids_count) AS M_ids_count,
SUM(t.A_ids_count) AS A_ids_count,
SUM(IF(t.M_trip_count = 'M_NULL', 0, (IF(t.M_trip_count = 'M_SAME', t.M_ids_count, 1)))) AS M_trip_count,
SUM(IF(t.A_trip_count = 'A_NULL', 0, (IF (t.A_trip_count = 'A_SAME', t.A_ids_count, 1)))) AS A_trip_count
FROM (
SELECT
date_part AS dp,
SUM(CASE WHEN day_part = 'M' THEN 1 ELSE 0 END) AS M_ids_count,
SUM(CASE WHEN day_part = 'A' THEN 1 ELSE 0 END) AS A_ids_count,
(CASE WHEN (day_part = 'M') THEN (IF(((id_a = 0 AND id_b = 0) OR (id_a = id_b)), 'M_SAME', 'M_DIFF')) ELSE 'M_NULL' END) AS M_trip_count,
(CASE WHEN (day_part = 'A') THEN (IF(((id_a = 0 AND id_b = 0) OR (id_a = id_b)), 'A_SAME', 'A_DIFF')) ELSE 'A_NULL' END) AS A_trip_count
FROM timer
WHERE date_part BETWEEN '2015-11-30' AND '2015-12-06' AND day_part IN ("M", "A")
GROUP BY id_a,id_b,M_trip_count,A_trip_count
) AS t
GROUP BY t.dp
This will work as per below table structure, which you have specified in above table.
CREATE TABLE IF NOT EXISTS `timer` (
`id` int(11) NOT NULL,
`id_a` int(11) NOT NULL,
`id_b` int(11) NOT NULL,
`date_part` date NOT NULL,
`day_part` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `timer` (`id`, `id_a`, `id_b`, `date_part`, `day_part`) VALUES
(32043, 0, 0, '2015-12-03', 'A'),
(31933, 0, 31933, '2015-12-03', 'A'),
(31908, 0, 0, '2015-12-03', 'A'),
(31384, 0, 31384, '2015-11-30', 'M'),
(31335, 0, 0, '2015-11-30', 'M'),
(31303, 0, 31303, '2015-11-30', 'M'),
(31302, 0, 0, '2015-11-30', 'M'),
(31300, 0, 0, '2015-11-30', 'M'),
(31223, 0, 0, '2015-12-03', 'A'),
(31221, 0, 31221, '2015-11-30', 'M'),
(32037, 0, 32037, '2015-12-03', 'A'),
(31301, 31301, 0, '2015-11-30', 'M'),
(31901, 31301, 0, '2015-11-30', 'M');
Upvotes: 1