I am trying to bin my data to see how it is distributed. Some bins contain no data. So, when I query my bins, I only get the bins containing data. I would like the query to also show empty bins.
I was trying to create a table containing all the bins to latter do a LEFT JOIN with the query containing data from my table. But I still only get bins with data. The query does not show empty bins. This is the code I was using:
WITH tb AS
(
SELECT 'A [+0 min-1 min]' AS bins UNION ALL
SELECT 'B [+1 min-113 min]' UNION ALL
SELECT 'C [+113 min-223 min]' UNION ALL
SELECT 'D [+223 min-335 min]' UNION ALL
SELECT 'E [+335 min-447 min]' UNION ALL
SELECT 'F [+447 min-559 min]' UNION ALL
SELECT 'G [+559 min-671 min]' UNION ALL
SELECT 'H [+671 min-783 min]' UNION ALL
SELECT 'I [+783 min-895 min]' UNION ALL
SELECT 'J [+895 min-1007 min]' UNION ALL
SELECT 'K [+1007 min-1119 min]' UNION ALL
SELECT 'L [+1119 min-1231 min]' UNION ALL
SELECT 'M [+1231 min-1343 min]' UNION ALL
SELECT 'N [+1343 min-1440 min]' UNION ALL
SELECT 'O [+1140 min]'
), aa AS
(
SELECT CASE
WHEN ride_length BETWEEN '00:00:00' AND '00:01:00' THEN
'A [+0 min-1 min]'
WHEN ride_length BETWEEN '00:01:01' AND '01:53:00' THEN
'B [+1 min-113 min]'
WHEN ride_length BETWEEN '01:53:01' AND '03:43:00' THEN
'C [+113 min-223 min]'
WHEN ride_length BETWEEN '03:43:01' AND '05:35:00' THEN
'D [+223 min-335 min]'
WHEN ride_length BETWEEN '05:35:01' AND '07:27:00' THEN
'E [+335 min-447 min]'
WHEN ride_length BETWEEN '07:27:01' AND '09:19:00' THEN
'F [+447 min-559 min]'
WHEN ride_length BETWEEN '09:19:01' AND '11:11:00' THEN
'G [+559 min-671 min]'
WHEN ride_length BETWEEN '11:11:01' AND '13:03:00' THEN
'H [+671 min-783 min]'
WHEN ride_length BETWEEN '13:03:01' AND '14:55:00' THEN
'I [+783 min-895 min]'
WHEN ride_length BETWEEN '14:55:01' AND '16:47:00' THEN
'J [+895 min-1007 min]'
WHEN ride_length BETWEEN '16:47:01' AND '18:39:00' THEN
'K [+1007 min-1119 min]'
WHEN ride_length BETWEEN '18:39:01' AND '20:31:00' THEN
'L [+1119 min-1231 min]'
WHEN ride_length BETWEEN '20:31:01' AND '22:23:00' THEN
'M [+1231 min-1343 min]'
WHEN ride_length BETWEEN '22:33:01' AND '24:00:00' THEN
'N [+1343 min-1440 min]'
ELSE
'O [+1140 min]'
END AS bins,
member_casual,
rideable_type
FROM (SELECT TIMEDIFF(ended_at, started_at) AS ride_length,
member_casual,
rideable_type
FROM cyclistic) a
)
SELECT tb.bins,
aa.member_casual,
aa.rideable_type,
IFNULL(COUNT(member_casual), 0)
FROM tb
LEFT JOIN aa
ON tb.bins = aa.bins
GROUP BY tb.bins, aa.member_casual, aa.rideable_type;
For some reason, the output I get is the following:
+------------------------+---------------+---------------+--------------------------------+
| bins | member_casual | rideable_type | IFNULL(COUNT(member_casual),0) |
+------------------------+---------------+---------------+--------------------------------+
| classic_bike | 25999 |
| electric_bike | 47882 |
| classic_bike | 12892 |
| electric_bike | 33882 |
| electric_bike | 1213471 |
| electric_bike | 1584591 |
| classic_bike | 1679971 |
| classic_bike | 857810 |
| docked_bike | 158858 |
| classic_bike | 15025 |
| electric_bike | 2426 |
| docked_bike | 11824 |
| classic_bike | 1661 |
| electric_bike | 635 |
| classic_bike | 400 |
| electric_bike | 184 |
| classic_bike | 84 |
| classic_bike | 38 |
| docked_bike | 195 |
| docked_bike | 1554 |
| classic_bike | 1213 |
| electric_bike | 323 |
| docked_bike | 139 |
| classic_bike | 25 |
| classic_bike | 42 |
| docked_bike | 263 |
| classic_bike | 111 |
| classic_bike | 213 |
| docked_bike | 192 |
| classic_bike | 159 |
| classic_bike | 113 |
| electric_bike | 5263 |
| classic_bike | 176 |
| classic_bike | 400 |
| electric_bike | 64 |
| docked_bike | 443 |
| docked_bike | 169 |
| classic_bike | 131 |
| classic_bike | 194 |
| classic_bike | 275 |
| docked_bike | 207 |
| classic_bike | 129 |
| electric_bike | 1 |
| docked_bike | 152 |
| classic_bike | 80 |
| classic_bike | 126 |
| classic_bike | 2606 |
| docked_bike | 1507 |
| classic_bike | 716 |
| docked_bike | 201 |
| classic_bike | 94 |
| classic_bike | 47 |
| docked_bike | 1528 |
| electric_bike | 168 |
| docked_bike | 229 |
| classic_bike | 137 |
| classic_bike | 287 |
| electric_bike | 51 |
+------------------------+---------------+---------------+--------------------------------+
I also tried COALESCE, but I got the same output.
Just define your bins in one place and then use that to LEFT JOIN to cyclistic:
WITH bins (bin, start, end) AS (
SELECT 'A [+0 min-1 min]', '00:00:00', '00:01:00' UNION ALL
SELECT 'B [+1 min-113 min]', '00:01:01', '01:53:00' UNION ALL
SELECT 'C [+113 min-223 min]', '01:53:01', '03:43:00' UNION ALL
SELECT 'D [+223 min-335 min]', '03:43:01', '05:35:00' UNION ALL
SELECT 'E [+335 min-447 min]', '05:35:01', '07:27:00' UNION ALL
SELECT 'F [+447 min-559 min]', '07:27:01', '09:19:00' UNION ALL
SELECT 'G [+559 min-671 min]', '09:19:01', '11:11:00' UNION ALL
SELECT 'H [+671 min-783 min]', '11:11:01', '13:03:00' UNION ALL
SELECT 'I [+783 min-895 min]', '13:03:01', '14:55:00' UNION ALL
SELECT 'J [+895 min-1007 min]', '14:55:01', '16:47:00' UNION ALL
SELECT 'K [+1007 min-1119 min]', '16:47:01', '18:39:00' UNION ALL
SELECT 'L [+1119 min-1231 min]', '18:39:01', '20:31:00' UNION ALL
SELECT 'M [+1231 min-1343 min]', '20:31:01', '22:23:00' UNION ALL
SELECT 'N [+1343 min-1440 min]', '22:23:01', '24:00:00' UNION ALL
SELECT 'O [+1140 min]', '24:00:01', NULL
)
SELECT bins.bin,
c.member_casual,
c.rideable_type,
COUNT(c.id)
FROM bins
LEFT JOIN cyclistic c
ON TIMEDIFF(c.ended_at, c.started_at) BETWEEN bins.start AND bins.end
OR (bins.end IS NULL AND TIMEDIFF(ended_at, started_at) >= bins.start)
GROUP BY bins.bin, c.member_casual, c.rideable_type;
With the following CTE to represent your cyclistic table:
WITH cyclistic (id, member_casual, rideable_type, started_at, ended_at) AS (
SELECT 1, 1, 'classic_bike', '2023-02-11 00:00:00', '2023-02-11 00:00:01' UNION ALL
SELECT 2, 2, 'classic_bike', '2023-02-11 00:00:00', '2023-02-11 00:00:01' UNION ALL
SELECT 3, 1, 'classic_bike', '2023-02-11 00:00:00', '2023-02-12 00:00:01'
)
the query returns:
bin
member_casual
rideable_type
COUNT(c.id)
A [+0 min-1 min]
2
classic_bike
1
A [+0 min-1 min]
1
classic_bike
1
B [+1 min-113 min]
0
C [+113 min-223 min]
0
D [+223 min-335 min]
0
E [+335 min-447 min]
0
F [+447 min-559 min]
0
G [+559 min-671 min]
0
H [+671 min-783 min]
0
I [+783 min-895 min]
0
J [+895 min-1007 min]
0
K [+1007 min-1119 min]
0
L [+1119 min-1231 min]
0
M [+1231 min-1343 min]
0
N [+1343 min-1440 min]
0
O [+1140 min]
1
classic_bike
1
Obviously, this is a very inefficient query and you should be cautious if running this against a live OLTP database.
Related
Hi I am a beginner in my sql I will really appreciate any advice
I have main table
Address Val1 Mat
tbla 10 Mat1
tbla 2 Mat2
tbla 23 Mat3
tbla 5 Mat4
this rows need to be shown in each month like this
Output
Address Val1 Mat MonthCreated
tbla 10 Mat1 January
tbla 2 Mat2 January
tbla 23 Mat3 January
tbla 5 Mat4 January
tbla 10 Mat1 February
tbla 2 Mat2 February
tbla 23 Mat3 February
tbla 5 Mat4 February
up until december but i need to join the income from other table
my query is like this
SELECT dttry.*, all_months.*
FROM (SELECT
t1.Address,t1.mat,
COUNT( DISTINCT t1.id ) AS `Val1`,t1.mat as 'Mat'
, COALESCE(i.Income , 0 ) AS `Income`
FROM tbladds1 t1
JOIN tbladds1_type tt ON tt.id = t1.t_type_id
JOIN tbladdress m ON m.id = t1.t_mid
JOIN tbladdressfr mf ON mf.id = t1.t_floor_id
JOIN tblppl mp ON mp.t_mid = m.id
AND mp.t_type = 'try'
AND mp.t_system_id = 'ok'
left join (
SELECT
CAST( SUM(r.t_payment_total) AS decimal(18, 2) ) AS `Income`
FROM reserv r
INNER JOIN newtbladds1 t ON t.t_parent_id = r.id
WHERE r.t_status != 'Pending'
AND r.t_status != 'Booked'
AND r.c_mid = m.id AND (t.c_start_date) BETWEEN '2018/01/01' AND '2018/01/31'
GROUP BY
t.t_type_id
) as i on t1.t_type_id = i.t_type_id
->this is income for january
left join (
SELECT
CAST( SUM(r.t_payment_total) AS decimal(18, 2) ) AS `Income`
FROM reserv r
INNER JOIN newtbladds1 t ON t.t_parent_id = r.id
WHERE r.t_status != 'Pending'
AND r.t_status != 'Booked'
AND r.c_mid = m.id AND (t.c_start_date) BETWEEN '2018/02/01' AND '2018/02/31'
GROUP BY
t.t_type_id
) as ifebruary on t1.t_type_id = i.t_type_id
->this is income for february
GROUP BY
t1.t_tool_type_id) as dttry
CROSS JOIN
(SELECT 'January' AS MonthCreated UNION ALL
SELECT 'February' UNION ALL
SELECT 'March' UNION ALL
SELECT 'April' UNION ALL
SELECT 'May' UNION ALL
SELECT 'June' UNION ALL
SELECT 'July' UNION ALL
SELECT 'August' UNION ALL
SELECT 'September' UNION ALL
SELECT 'October' UNION ALL
SELECT 'November' UNION ALL
SELECT 'December') AS all_months
Output
Address Val1 Mat Income MonthCreated
tbla 10 Mat1 0 January
tbla 2 Mat2 30 January
tbla 23 Mat3 10 January
tbla 5 Mat4 0 January
tbla 10 Mat1 0 February
tbla 2 Mat2 30 February
tbla 23 Mat3 10 February
tbla 5 Mat4 0 February
but for the income column of february it should be not the same as january
it should be
income
1
2
7
8
Desired Output
Output
Address Val1 Income MonthCreated
tbla 10 0 January
tbla 2 30 January
tbla 23 10 January
tbla 5 0 January
tbla 10 1 February
tbla 2 2 February
tbla 23 7 February
tbla 5 8 February
It's not possible to give a full answer unless you can provide sample data from all your tables but you almost certainly do not need a sub query for every income month and I would make life simpler by unioning month numbers rather than names and then label afterward. For example
drop table if exists maintable;
create table maintable(
Address varchar(10), Val1 int, Mat varchar(10));
insert into maintable values
( 'tbla' , 10 , 'Mat1'),
( 'tbla' , 2 , 'Mat2'),
( 'tbla' , 23 , 'Mat3'),
( 'tbla' , 5 , 'Mat4');
drop table if exists income;
create table income(id int auto_increment primary key, mat varchar(10),dt date,amount int);
insert into income (mat,dt,amount) values
('mat2','2018-01-01',10),('mat2','2018-01-01',20),('mat3','2018-01-01',10),
('mat1','2018-02-01',1),('mat2','2018-02-01',7),('mat3','2018-02-01',8),('mat4','2018-02-01',9),
('mat3','2018-10-01',10);
select s.address,s.mat,s.val1,
coalesce(i.income,0) income,
case when s.monthcreated = 1 then 'jan'
when s.monthcreated = 2 then 'feb'
when s.monthcreated = 3 then 'mar'
when s.monthcreated = 4 then 'apr'
when s.monthcreated = 5 then 'may'
when s.monthcreated = 6 then 'jun'
when s.monthcreated = 7 then 'jul'
when s.monthcreated = 8 then 'aug'
when s.monthcreated = 9 then 'sep'
when s.monthcreated = 10 then 'oct'
when s.monthcreated = 11 then 'nov'
when s.monthcreated = 1 then 'dec'
end as mmm
from
(
select all_months.* , maintable.*
from
(SELECT 1 AS MonthCreated UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10 UNION ALL
SELECT 11 UNION ALL
SELECT 12) AS all_months
cross join maintable
) s
left join
(
select mat mati,month(dt) mm ,sum(Amount) income
from income
where dt between '2018-01-01' and '2018-12-31'
group by mat,month(dt)
) i
on i.mati = s.mat and i.mm = s.monthcreated
order by s.monthcreated,s.mat;
Where the income sub query works out which month the income is for per mat.
Result
+---------+------+------+--------+------+
| Address | Mat | Val1 | income | mmm |
+---------+------+------+--------+------+
| tbla | Mat1 | 10 | 0 | jan |
| tbla | Mat2 | 2 | 30 | jan |
| tbla | Mat3 | 23 | 10 | jan |
| tbla | Mat4 | 5 | 0 | jan |
| tbla | Mat1 | 10 | 1 | feb |
| tbla | Mat2 | 2 | 7 | feb |
| tbla | Mat3 | 23 | 8 | feb |
| tbla | Mat4 | 5 | 9 | feb |
| tbla | Mat1 | 10 | 0 | mar |
| tbla | Mat2 | 2 | 0 | mar |
| tbla | Mat3 | 23 | 0 | mar |
| tbla | Mat4 | 5 | 0 | mar |
| tbla | Mat1 | 10 | 0 | apr |
| tbla | Mat2 | 2 | 0 | apr |
| tbla | Mat3 | 23 | 0 | apr |
| tbla | Mat4 | 5 | 0 | apr |
| tbla | Mat1 | 10 | 0 | may |
| tbla | Mat2 | 2 | 0 | may |
| tbla | Mat3 | 23 | 0 | may |
| tbla | Mat4 | 5 | 0 | may |
| tbla | Mat1 | 10 | 0 | jun |
| tbla | Mat2 | 2 | 0 | jun |
| tbla | Mat3 | 23 | 0 | jun |
| tbla | Mat4 | 5 | 0 | jun |
| tbla | Mat1 | 10 | 0 | jul |
| tbla | Mat2 | 2 | 0 | jul |
| tbla | Mat3 | 23 | 0 | jul |
| tbla | Mat4 | 5 | 0 | jul |
| tbla | Mat1 | 10 | 0 | aug |
| tbla | Mat2 | 2 | 0 | aug |
| tbla | Mat3 | 23 | 0 | aug |
| tbla | Mat4 | 5 | 0 | aug |
| tbla | Mat1 | 10 | 0 | sep |
| tbla | Mat2 | 2 | 0 | sep |
| tbla | Mat3 | 23 | 0 | sep |
| tbla | Mat4 | 5 | 0 | sep |
| tbla | Mat1 | 10 | 0 | oct |
| tbla | Mat2 | 2 | 0 | oct |
| tbla | Mat3 | 23 | 10 | oct |
| tbla | Mat4 | 5 | 0 | oct |
| tbla | Mat1 | 10 | 0 | nov |
| tbla | Mat2 | 2 | 0 | nov |
| tbla | Mat3 | 23 | 0 | nov |
| tbla | Mat4 | 5 | 0 | nov |
| tbla | Mat1 | 10 | 0 | NULL |
| tbla | Mat2 | 2 | 0 | NULL |
| tbla | Mat3 | 23 | 0 | NULL |
| tbla | Mat4 | 5 | 0 | NULL |
+---------+------+------+--------+------+
48 rows in set (0.00 sec)
I have a query
SELECT GROUP, VALUE, UNIXTIME FROM TABLE1
that returns a table that looks like this:
GROUP VALUE UNIXTIME
A 866 1522540800
A 123 1525132800
A 100 1527811200
A 85 1530403200
A 77 1533081600
A 65 1535760000
B 376 1522540800
B 66 1525132800
B 45 1527811200
B 58 1530403200
B 42 1533081600
C 481 1522540800
C 68 1525132800
C 77 1527811200
C 50 1530403200
D 792 1522540800
D 126 1525132800
D 84 1527811200
E 1297 1522540800
E 203 1525132800
F 882 1522540800
How can I get a result that returns the same result, but where each row is divided by the first value in its own group.
So for example VALUE on
row1 should be 866/866 = 1
row2 should be 123/866 = 0.142
row3 = 100/866 = 0.115
Value on row7 (first row of group B) should be 376/376=1
row8 should be 66/376 = 0.176 etc
Consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(group_id INT NOT NULL
,unixtime INT NOT NULL
,value INT NOT NULL
,PRIMARY KEY(group_id,unixtime)
);
INSERT INTO my_table VALUES
(1 , 1522540800 , 866),
(1 , 1525132800 , 123),
(1 , 1527811200 , 100),
(1 , 1530403200 , 85),
(1 , 1533081600 , 77),
(1 , 1535760000 , 65),
(2 , 1522540800 , 376),
(2 , 1525132800 , 66),
(2 , 1527811200 , 45),
(2 , 1530403200 , 58),
(2 , 1533081600 , 42),
(3 , 1522540800 , 481),
(3 , 1525132800 , 68),
(3 , 1527811200 , 77),
(3 , 1530403200 , 50),
(4 , 1522540800 , 792),
(4 , 1525132800 , 126),
(4 , 1527811200 , 84),
(5 , 1522540800 , 1297),
(5 , 1525132800 , 203),
(6 , 1522540800 , 882);
SELECT x.*
, value/CASE WHEN #prev = group_id THEN #val:=#val ELSE #val:=value END val
, #prev:=group_id
FROM my_table x
,(SELECT #prev:=null,#val:=0) vars
ORDER
BY group_id
, unixtime;
+----------+------------+-------+--------+-----------------+
| group_id | unixtime | value | val | #prev:=group_id |
+----------+------------+-------+--------+-----------------+
| 1 | 1522540800 | 866 | 1.0000 | 1 |
| 1 | 1525132800 | 123 | 0.1420 | 1 |
| 1 | 1527811200 | 100 | 0.1155 | 1 |
| 1 | 1530403200 | 85 | 0.0982 | 1 |
| 1 | 1533081600 | 77 | 0.0889 | 1 |
| 1 | 1535760000 | 65 | 0.0751 | 1 |
| 2 | 1522540800 | 376 | 1.0000 | 2 |
| 2 | 1525132800 | 66 | 0.1755 | 2 |
| 2 | 1527811200 | 45 | 0.1197 | 2 |
| 2 | 1530403200 | 58 | 0.1543 | 2 |
| 2 | 1533081600 | 42 | 0.1117 | 2 |
| 3 | 1522540800 | 481 | 1.0000 | 3 |
| 3 | 1525132800 | 68 | 0.1414 | 3 |
| 3 | 1527811200 | 77 | 0.1601 | 3 |
| 3 | 1530403200 | 50 | 0.1040 | 3 |
| 4 | 1522540800 | 792 | 1.0000 | 4 |
| 4 | 1525132800 | 126 | 0.1591 | 4 |
| 4 | 1527811200 | 84 | 0.1061 | 4 |
| 5 | 1522540800 | 1297 | 1.0000 | 5 |
| 5 | 1525132800 | 203 | 0.1565 | 5 |
| 6 | 1522540800 | 882 | 1.0000 | 6 |
+----------+------------+-------+--------+-----------------+
21 rows in set (0.00 sec)
Try the following (will work for all versions of MySQL, especially < 8.0):
SELECT t3.*, t3.VALUE / t2.FIRST_VALUE AS RATIO
FROM TABLE1 AS t3
INNER JOIN (SELECT t1.GROUP,
t1.VALUE AS FIRST_VALUE
FROM TABLE1 AS t1
WHERE t1.UNIXTIME = (SELECT MIN(UNIXTIME)
FROM TABLE1 AS t4
WHERE t4.GROUP = t1.GROUP)
GROUP BY t1.GROUP) AS t2 ON t2.GROUP = t3.GROUP
Another possible solution utilizing GROUP_CONCAT and string operations is:
SELECT t3.*, t3.VALUE / t2.FIRST_VALUE AS RATIO
FROM TABLE1 AS t3
INNER JOIN (SELECT t1.GROUP,
CAST(SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT t1.VALUE ORDER BY t1.UNIXTIME ASC SEPARATOR ','), ',', 1) AS UNSIGNED) AS FIRST_VALUE
FROM TABLE1 AS t1
GROUP BY t1.GROUP) AS t2 ON t2.GROUP = t3.GROUP
Note: You might need to increase the group_concat_max_len if you have more values in a particular group.
I have next data:
mysql> select no,crt_date,tobilling_date,sent_to_client,dop_prov from assistfin limit 20;
+--------+---------------------+---------------------+----------------+------------+
| no | crt_date | tobilling_date | sent_to_client | dop_prov |
+--------+---------------------+---------------------+----------------+------------+
| 50.01 | 2014-02-05 10:28:10 | 2014-02-05 14:42:35 | 2014-04-16 | 2014-09-23 |
| 123.01 | 2014-02-05 19:17:36 | 2014-03-17 18:58:05 | 2014-04-10 | 2014-06-30 |
| 51.01 | 2014-02-06 00:09:32 | 2014-03-20 16:53:46 | 2014-04-10 | 2014-06-30 |
| 124.01 | 2014-02-06 15:29:08 | 2014-03-20 17:04:42 | 2014-04-10 | 2014-06-30 |
| 230.01 | 2014-02-07 22:01:11 | 2014-03-20 16:41:03 | 2014-04-10 | 2014-06-30 |
| 252.01 | 2014-02-08 02:52:33 | 2014-03-20 16:43:03 | 2014-04-10 | 2014-06-30 |
| 123.02 | 2014-02-08 03:00:52 | 2014-03-17 18:58:10 | 2014-04-10 | 2014-06-30 |
| 213.01 | 2014-02-08 04:01:35 | 2014-03-26 19:03:01 | 2014-04-10 | 2014-09-19 |
| 55.01 | 2014-02-08 21:04:45 | 2014-03-07 18:40:46 | NULL | 2014-06-26 |
| 126.01 | 2014-02-08 21:46:58 | 2014-09-02 18:39:36 | 2014-09-09 | 2014-09-26 |
| 284.01 | 2014-02-09 01:52:54 | 2014-06-11 19:11:06 | 2014-07-02 | 2014-07-21 |
| 261.01 | 2014-02-09 02:20:34 | 2014-03-17 20:57:39 | 2014-04-10 | 2014-06-30 |
| 318.01 | 2014-02-09 03:09:28 | 2014-03-17 20:44:25 | 2014-04-10 | 2014-06-30 |
| 225.01 | 2015-02-10 03:21:08 | 2014-03-20 16:57:56 | 2014-04-10 | 2014-06-30 |
| 248.01 | 2014-02-09 03:30:58 | 2014-03-18 18:02:21 | 2014-04-10 | 2014-06-30 |
| 178.01 | 2014-04-05 03:35:25 | 2014-03-21 17:10:12 | 2014-04-10 | 2014-06-30 |
| 184.01 | 2014-04-08 04:01:13 | 2015-03-20 16:38:02 | 2015-04-10 | 2015-06-30 |
| 320.01 | 2014-04-08 05:57:23 | 2015-03-17 20:49:19 | 2015-04-10 | 2015-06-30 |
| 230.02 | 2015-05-08 06:18:15 | 2016-03-20 16:41:08 | 2016-04-10 | 2016-06-06 |
| 325.01 | 2014-05-09 06:23:50 | 2015-03-17 20:42:04 | 2015-04-10 | 2015-06-30 |
+--------+---------------------+---------------------+----------------+------------+
Need to get next data:
+---------+---------+--------+-----------+---------+
| year | Created | Passed | To client | To prov |
+---------+---------+--------+-----------+---------+
| 2016-01 | 1901 | 1879 | 1873 | 1743 |
| 2016-02 | 2192 | 2169 | 2114 | 1912 |
| 2016-03 | 2693 | 2639 | 2539 | 2309 |
| 2016-04 | 2634 | 2574 | 2273 | 1976 |
| 2016-05 | 2593 | 2497 | 1109 | 949 |
| 2016-06 | 471 | 449 | 2 | 78 |
+---------+---------+--------+-----------+---------+
Where year like DATE_FORMAT(curdate(), '%Y-%m'), next column Count(assistfin.crt_date) as Created.
The problem is that crt_date can be like 2015%, but sent_to_client or dop_prov can be like 2016%.
How to make correct query?
Ok sorry this is so long and messy and also I couldnt do it using unions as I so arrogantly posted in the comments, also have to reference MySQL: Is it possible to 'fill' a SELECT with values without a table? that gave me the list of months. You could rewrite it so you left join all the tables to crt_date, but then it wont show a month when nothing was created, hence the generated months table. The original query had a limit 120 in the months, but I have replaced it with a datetime > '2014' for you to change with your earliest date.
Try this and see how quickly it runs for you.
select Months.yearmonth, created, passed, to_client, to_prov
from
(SELECT date_format(datetime,'%Y-%m') as yearmonth
FROM (
select (curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) MONTH) as datetime
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) AS t
where datetime > '2014' -- enter your earliest year here
ORDER BY datetime ASC) Months left join
(select date_format(crt_date,'%Y-%m') as yearmonth, count(no) as "created" from assistfin group by yearmonth) created on Months.yearmonth=created.yearmonth
left join
(select date_format(tobilling_date,'%Y-%m') as yearmonth, count(no) as "passed" from assistfin group by yearmonth) passed on Months.yearmonth=passed.yearmonth
left join
(select date_format(sent_to_client,'%Y-%m') as yearmonth, count(no) as "to_client" from assistfin group by yearmonth) to_client on Months.yearmonth=to_client.yearmonth
left join
(select date_format(dop_prov,'%Y-%m') as yearmonth, count(no) as "to_prov" from assistfin group by yearmonth) to_prov on Months.yearmonth=to_prov.yearmonth
where
group by yearmonth;
Use group by and date_forma in where
select date_format(crt_date, '%Y-%m') as year, count(sent_to_client ), count(dop_pprov)
from assistfin
where date_format(crt_date, '%Y-%m') = date_format(now(), '%Y-%m')
group by year
for the year you can
select date_format(crt_date, '%Y-%m') as year, count(sent_to_client ), count(dop_pprov)
from assistfin
where date_format(crt_date, '%Y') = date_format(now(), '%Y')
group by year
OR for A Range OF yearS you can
select date_format(crt_date, '%Y-%m') as year, count(sent_to_client ), count(dop_pprov)
from assistfin
where date_format(crt_date, '%Y')
BETWEEN(date_format(now(),'%Y')-2) and date_format(now(), '%Y')
group by year
I have a table which has 3 columns: Category, Seller, Sales
catgeory seller Sales
a ab 1654
a bc 1656
a cd 1136
a da 1421
a ef 1309
a gh 1624
b cd 1754
b hj 1542
b kl 1925
b mn 1915
c op 1912
c ab 1335
c de 1079
c pq 1316
d ag 1890
d df 1817
and i just want the list of the sellers who are contributing top 40% of the sales in each category.Using Mysql query. any ideas?
I'm thinking it would be something along the lines of this:
select seller
from table
where sales IN (
select max(sales)
from table
group by category)
Consider the following. This schema assumes a PK on (category,seller)...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(category CHAR(1) NOT NULL
,seller CHAR(2) NOT NULL
,Sales INT NOT NULL
,PRIMARY KEY(category,seller)
);
INSERT INTO my_table VALUES
('a' , 'ab' , 1654),
('a' , 'bc' , 1656),
('a' , 'cd' , 1136),
('a' , 'da' , 1421),
('a' , 'ef' , 1309),
('a' , 'gh' , 1624),
('b' , 'cd' , 1754),
('b' , 'hj' , 1542),
('b' , 'kl' , 1925),
('b' , 'mn' , 1915),
('c' , 'op' , 1912),
('c' , 'ab' , 1335),
('c' , 'de' , 1079),
('c' , 'pq' , 1316),
('d' , 'ag' , 1890),
('d' , 'df' , 1817);
Here's an intermediate solution. It gets you a running total of the percentage contribution made by each seller.
SELECT a.category
, a.seller
, a.sales
, IF(category = #prev,#pct := #pct + a.pct,#pct:=pct) total
, #prev := category
FROM
( SELECT x.*
, SUM(DISTINCT x.sales)/SUM(y.sales) pct
FROM my_table x
JOIN my_table y
ON y.category = x.category
GROUP
BY x.category
, x.seller
) a
, (SELECT #pct := 0,#prev:='') vars
ORDER
BY a.category
, a.pct DESC;
+----------+--------+-------+--------+-------------------+
| category | seller | sales | total | #prev := category |
+----------+--------+-------+--------+-------------------+
| a | bc | 1656 | 0.1882 | a |<--
| a | ab | 1654 | 0.3762 | a |<-- Desired users
| a | gh | 1624 | 0.5607 | a |<--
| a | da | 1421 | 0.7222 | a |
| a | ef | 1309 | 0.8710 | a |
| a | cd | 1136 | 1.0001 | a |
| b | kl | 1925 | 0.2698 | b |<--
| b | mn | 1915 | 0.5382 | b |<--
| b | cd | 1754 | 0.7840 | b |
| b | hj | 1542 | 1.0001 | b |
| c | op | 1912 | 0.3389 | c |<--
| c | ab | 1335 | 0.5755 | c |<--
| c | pq | 1316 | 0.8088 | c |
| c | de | 1079 | 1.0000 | c |
| d | ag | 1890 | 0.5098 | d |<--
| d | df | 1817 | 1.0000 | d |
+----------+--------+-------+--------+-------------------+
A complete solution reverses the logic by discounting users who fail to contribute 60 percent...
SELECT n.category
, n.seller
, n.sales
FROM
( SELECT a.category
, a.seller
, a.sales
, IF(category = #prev,#pct := #pct + a.pct,#pct:=pct) total
, #prev := category
FROM
( SELECT x.*
, SUM(DISTINCT x.sales)/SUM(y.sales) pct
FROM my_table x
JOIN my_table y
ON y.category = x.category
GROUP
BY x.category
, x.seller
) a
, (SELECT #pct := 0,#prev:='') vars
ORDER
BY a.category
, a.pct -- <-- reversed
) n
WHERE total >= 0.6
ORDER BY category,sales DESC;
+----------+--------+-------+
| category | seller | sales |
+----------+--------+-------+
| a | bc | 1656 |
| a | ab | 1654 |
| a | gh | 1624 |
| b | kl | 1925 |
| b | mn | 1915 |
| c | op | 1912 |
| c | ab | 1335 |
| d | ag | 1890 |
+----------+--------+-------+
id | name | elapsed
1 James 0
2 John 60
3 Kerry 60
4 Janet 60
5 Katie 60
Based on the results above , how can I select names where the 'elapsed' value total is less than or equal to 120? For those results, that would involve selecting the names 'James', 'John' and 'Kerry'. If I changed the total elapsed to 180 it would also select 'Janet'.
How can I construct a query that returns this?
This should work:
SELECT
t1.id,
t1.name,
t1.elapsed
FROM your_table t1
INNER JOIN your_table t2 ON (t1.id >= t2.id)
GROUP BY t1.id, t1.name, t1.elapsed
HAVING SUM(t2.elapsed) <= 120
Here's something to think about...
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT i,#x:=#x+i running FROM ints i,(SELECT #x:=0)var ORDER BY i;
+---+----------+
| i | running |
+---+----------+
| 0 | 0 |
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
| 5 | 15 |
| 6 | 21 |
| 7 | 28 |
| 8 | 36 |
| 9 | 45 |
+---+----------+
SELECT
*
FROM (
SELECT '1' AS ID, 'James' AS Name, 0 AS Elapsed
UNION ALL SELECT '2', 'John', 60
UNION ALL SELECT '3', 'Kerry', 60
UNION ALL SELECT '4', 'Janet', 60
UNION ALL SELECT '5', 'Katie', 60
) AS X
WHERE 1=1
AND (
SELECT SUM(Elapsed)
FROM (
SELECT '1' AS ID, 'James' AS Name, 0 AS Elapsed
UNION ALL SELECT '2', 'John', 60
UNION ALL SELECT '3', 'Kerry', 60
UNION ALL SELECT '4', 'Janet', 60
UNION ALL SELECT '5', 'Katie', 60
) AS Y
WHERE Y.ID <= X.ID
) <= 180
ORDER BY ID