MYSQL query better way to group by if values? - mysql

I have a working query, but there has to be a better way to do this.
Here is the working query
SELECT gameid FROM(
SELECT gameid, SUM(count) as total FROM (
SELECT IF(vanguard = 1, 30, gameid) as gameid, count FROM (
SELECT opserv_operation.gameid, opserv_games.vanguard, COUNT(opserv_games.gameid) AS count FROM opserv_operation_attendees INNER JOIN opserv_operation ON opserv_operation_attendees.operationid = opserv_operation.operationid INNER JOIN opserv_games on opserv_operation.gameid = opserv_games.gameid WHERE (start_time >= '2015-11-11' || FIND_IN_SET(opserv_operation.operationid, '17951,17701,17702,17775,17969,17890,17958,17966,17900')) AND completed = 1 AND opserv_operation_attendees.userid = 5750 AND opserv_operation_attendees.status = 4 AND opserv_operation.type <> 5 AND opserv_operation.completed = 1 GROUP BY opserv_operation.gameid) as m
) as l
GROUP BY gameid
ORDER BY total DESC LIMIT 1) as k
The main query
SELECT opserv_operation.gameid, opserv_games.vanguard, COUNT(opserv_games.gameid) AS count FROM opserv_operation_attendees INNER JOIN opserv_operation ON opserv_operation_attendees.operationid = opserv_operation.operationid INNER JOIN opserv_games on opserv_operation.gameid = opserv_games.gameid WHERE (start_time >= '2015-11-11' || FIND_IN_SET(opserv_operation.operationid, '17951,17701,17702,17775,17969,17890,17958,17966,17900')) AND completed = 1 AND opserv_operation_attendees.userid = 5750 AND opserv_operation_attendees.status = 4 AND opserv_operation.type <> 5 AND opserv_operation.completed = 1 GROUP BY opserv_operation.gameid
gameid vanguard
16 0
36 1
36 1
36 1
16 0
36 1
27 0
16 0
36 1
36 1
36 1
30 0
36 1
36 1
27 0
36 1
36 1
36 1
So here is the tricky part. I need it to group by and count all the values however if gameid = 30 or vanguard = 1 then they should be all counted together.
So with the above data, the only thing I need is the gameid returned in this case gameid 30. It would have the most counts which would be 13.
There has to be a better way than I have done it.
Edit: So far this one works great thanks to Ed Gibbs. However is still returns two values, I'm guessing only way is to have another subquery? to get just gameid.
SELECT
CASE WHEN vanguard = 1 THEN 30 ELSE gameid END AS gameid,
SUM(count) AS total
FROM (SELECT opserv_operation.gameid, opserv_games.vanguard, COUNT(opserv_games.gameid) AS count FROM opserv_operation_attendees INNER JOIN opserv_operation ON opserv_operation_attendees.operationid = opserv_operation.operationid INNER JOIN opserv_games on opserv_operation.gameid = opserv_games.gameid WHERE (start_time >= '2015-11-11' || FIND_IN_SET(opserv_operation.operationid, '17951,17701,17702,17775,17969,17890,17958,17966,17900')) AND completed = 1 AND opserv_operation_attendees.userid = 5750 AND opserv_operation_attendees.status = 4 AND opserv_operation.type <> 5 AND opserv_operation.completed = 1 GROUP BY opserv_operation.gameid) as l
GROUP BY CASE WHEN vanguard = 1 THEN 30 ELSE gameid END
ORDER BY total DESC
LIMIT 1;

If bottom line you mean "1" and "30" have to be counted together then this should work:
SELECT
CASE WHEN vanguard = 1 THEN 30 ELSE gameid END AS gameid
FROM (... main query ...)
GROUP BY CASE WHEN gameid = 1 THEN 30 ELSE gameid END
ORDER BY SUM(count) DESC
LIMIT 1;

Related

remove repeated users from rank with group by

I am trying to rank from a table users. This table contains a log of all results. I already can rank the elements depending on the result ASC, but I have repeated users ID that I want to group by but I can't.
ID_competitionLog ID_event ID_athlete result wind rank
4 19 2 49.12 NULL 1
6 19 11 49.56 NULL 2
13 19 1 50.12 NULL 4
17 4 1 49.8 NULL 3
SELECT *, FIND_IN_SET( result, ( SELECT GROUP_CONCAT( result ORDER BY result ASC )
FROM competitionlog where (ID_event = 19 or ID_event = 4) and (result <> 0.0125 and result <> 0.00125 and result <> 0.000125))) AS rank
FROM competitionlog where (ID_event = 19 or ID_event = 4) and (result <> 0.0125 and result <> 0.00125 and result <> 0.000125);
I try to group by the repeated users and get only theirs best result to compare in the ranking

get last completed (some condition) id while counting

I'm trying to get the last completed task id of the child table while counting all the child records and completed child records:
set #tmp := 0;
select
count(*) total,
count(if(completed=1, 1, null)) completed,
#tmp:=if(completed=1, task_id, #tmp) last_completed_task_id
from child_table where parent_id = 6
order by sequence
Here is some sample data:
id parent_id completed task_id sequence
526 6 1 1 1
1653 6 0 5 2
2749 6 0 20 3
3840 6 0 21 4
4913 6 1 22 5
5983 6 0 23 6
7063 6 0 25 7
7183 6 0 26 8
8241 6 1 27 9
9317 6 0 28 10
10380 6 0 29 11
So final result should be like that:
total: 11
completed: 3
last_completed_task_id: 27
I know how to get it with separate queries, but I wish to get it with one query if possible.
You could use a cros join between the count and the max task_id eg:
select
count(*) total,
count(if(completed=1, 1, null)) completed,
t.last_completed_task_id
from child_table
cross join (
select max(task_id) last_completed_task_id
from child_table
where parent_id = 6
and completed=1 ) t
where parent_id = 6
You can easily get the last completed id using conditional aggregation:
select count(*),
sum(is_completed = 1),
max(case when is_completed = 1 then id end) as last_completed_id
from child_table ct
where parent_id = 6;
If task_id is increasing -- as in your sample data -- you can just use task_id rather than id in the max().
Otherwise, just join the table back in:
select cnt, cnt_completed, ct2.task_id
from (select count(*) as cnt,
sum(is_completed = 1) as cnt_completed,
max(case when is_completed = 1 then id end) as last_completed_id
from child_table ct
where parent_id = 6
) x join
child_table ct2
on x.last_completed_id = ct2.id
You could try this :
select count(*) total,
count(if(completed=1, 1, null)) completed,
(select task_id from child_table where parent_id = 6 and completed = 1 order by sequence desc limit 1) as last_completed_task_id
from child_table
where parent_id = 6

MySql : How do I have Horizontal Union of results?

I am looking to generate the results into the horizontal union. I could able to combine together and generate the results. However, I need to show the results in the expected results format.
SQL
(SELECT
kpa_id AS 'KPA', SUM(weightage) AS 'Total'
FROM
pmm_question_details
WHERE
weightage NOT LIKE '%-%'
GROUP BY kpa_id) UNION (SELECT
kpa_id AS 'KPA', SUM(weightage_value) AS 'Acheived'
FROM
pmm_answer_details
WHERE
application_id = 2
AND archive_value = 'No'
GROUP BY kpa_id)
Actual Results
1 14
2 37
3 19
4 40
5 51
6 24
1 12
2 19
3 0
6 2
Expected Results
1 14 1 12
2 37 2 19
3 19 3 0
4 40 6 2
5 51
6 24
If we can assume pmm_question_Details will always have as many or more records than pmm_answer_details... then two subqueries and a left join should do the trick with a join on a uservariable rownum (RN)
SELECT A.KPA, A.Total, B.KPA, B.Acheived
FROM (SELECT kpa_id AS 'KPA'
, SUM(weightage) AS 'Total'
, #RN1 := #RN1 + 1 as RN
FROM pmm_question_details
CROSS JOIN (SELECT #RN1 :=0) r1
WHERE weightage NOT LIKE '%-%'
ORDER BY KPA
GROUP BY kpa_id) A
LEFT JOIN (SELECT kpa_id AS 'KPA'
, SUM(weightage_value) AS 'Acheived'
, #RN1 := #RN2 + 1 as RN
FROM pmm_answer_details
CROSS JOIN (SELECT #RN2 :=0) r2
WHERE application_id = 2
AND archive_value = 'No'
ORDER BY KPA
GROUP BY kpa_id) B
on A.RN = B.RN
ORDER BY A.KPA
Though I must admit I don't see why a rownumber is needed if you could just left join on the KPA_ID in the first place...
if this could be the Expected results... (and again assuming pmm_question has all the IDs which could be in pmm_answer... )
Expected Results
1 14 1 12
2 37 2 19
3 19 3 0
4 40
5 51
6 24 6 2
Then the query would just be...
SELECT A.KPA, A.Total, B.KPA, B.Acheived
FROM (SELECT kpa_id AS 'KPA', SUM(weightage) AS 'Total'
FROM pmm_question_details
WHERE weightage NOT LIKE '%-%'
GROUP BY kpa_id) A
LEFT JOIN (SELECT kpa_id AS 'KPA', SUM(weightage_value) AS 'Acheived'
FROM pmm_answer_details
WHERE application_id = 2
AND archive_value = 'No'
GROUP BY kpa_id) B
on A.KPA = B.KPA

Get max and min values along with all values and multiple where clause

I have this query which works very good
SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
FROM chat_messages cm
WHERE TIMESTAMPDIFF(SECOND,cm.date_edited,'$now') < 10 GROUP BY cm.id
Which gives me the entries which are edited in less then 10 seconds.
But along with that im trying to get also the max(voteup) and min(votedown)
But dont affect the first entries of the first query . How can i combine then to get all entries i need ?
Example:
if im getting 3 newly updates entries . i want to get them those 3 plus the max of voteup and votedown .
Example:
id edited date_edited voteup votedown
37 0 2016-03-05 22:13:03 5 0
38 0 2016-04-02 11:15:00 3 7
39 0 2016-03-05 22:10:06 10 6
40 0 2016-03-20 21:40:06 5 0
41 1 2016-04-20 22:28:59 5 0
42 1 2016-03-20 21:59:15 0 20
43 1 2016-04-21 22:20:25 8 0 <---- this new updated
My wished result is
id edited date_edited voteup votedown maxup maxdown
39 0 2016-03-05 22:10:06 10 6 10 NULL
42 1 2016-03-20 21:59:15 0 20 NUll 20
43 1 2016-04-21 22:20:25 8 0 NULL NULL
My $now time is 2016-04-21 22:20:20
explanation:
-id 39 is having maxup vote i want get it
-id 42 is having maxdown i want get it
-id 43 is newly updated in that period of 10 seconds.
so i general i want get new updated entries pls the max up and down .
if many max voteup values are same then just choose one which have min votedown
Any solution to that pls ?
Here my sqlfiddle example
Edit: oh sorry i meant id . now wish my question is clear like
you will want to use a UNION statement:
SELECT * FROM (
select cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
, voteup as maxup, null AS maxdown
from chat_messages cm
ORDER BY voteup DESC, votedown
LIMIT 1
) a
UNION
SELECT * FROM (
select cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
, null as maxup, votedown AS maxdown
from chat_messages cm
ORDER BY votedown DESC, voteup
LIMIT 1
) b
UNION
SELECT * FROM (
SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
, null as maxup, null AS maxdown
from chat_messages cm
WHERE TIMESTAMPDIFF(SECOND,cm.date_edited,'2016-04-21 22:20:20') < 10
) c
note that I used '2016-04-21 22:20:20', but you will want to substitute the $now back in
you can use user-defined variables to track your maximums and then outer query the rows that match your rules.
SELECT id,edited,date_edited,voteup,votedown,
IF(voteup=#maxvoteup,voteup,NULL) as maxvoteup,
IF(votedown=#maxvotedown,votedown,NULL) as maxvotedown
FROM (SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown,
#maxvoteup := GREATEST(#maxvoteup,cm.voteup) as maxvoteup,
#maxvotedown := GREATEST(#maxvotedown,cm.votedown) as maxvotedown
FROM chat_messages cm,(SELECT #maxvoteup:=0,#maxvotedown:=0)initial
)T
WHERE TIMESTAMPDIFF(SECOND,date_edited,'2016-04-21 22:20:25') < 10
OR voteup = #maxvoteup
OR votedown = #maxvotedown
ORDER BY id ASC
sqlfiddle
Here's another query that is much more CRAZY..but it works ..
for maxupvote row, it'll find row that has maxupvote and minimum down vote, if more than 1 row exists (in a tie) it'll grab the row with latest/largest id.
for maxdownvote row, it'll find row that has maxdownvote and minimum up vote,
if more than 1 row exists (in a tie) it'll grab the row with latest/largest id.
SELECT id,edited,date_edited,voteup,votedown,
IF(voteup=#maxvoteup,voteup,NULL) as maxvoteup,
IF(votedown=#maxvotedown,votedown,NULL) as maxvotedown
FROM (SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown,
#minvotedown :=
(CASE WHEN cm.voteup > #maxvoteup OR (cm.voteup = #maxvoteup AND cm.votedown < #minvotedown)
THEN cm.votedown
ELSE #minvotedown
END),
#minvoteup :=
(CASE WHEN cm.votedown > #maxvotedown OR (cm.votedown = #maxvotedown AND cm.voteup < #minvoteup)
THEN cm.voteup
ELSE #minvoteup
END),
#maxvoteup := GREATEST(#maxvoteup,cm.voteup) as maxvoteup,
#maxvotedown := GREATEST(#maxvotedown,cm.votedown) as maxvotedown,
#maxvoteupid :=
(CASE WHEN cm.voteup = #maxvoteup AND cm.votedown = #minvotedown
THEN cm.id
ELSE #maxvoteupid
END),
#maxvotedownid :=
(CASE WHEN cm.votedown = #maxvotedown AND cm.voteup = #minvoteup
THEN cm.id
ELSE #maxvotedownid
END)
FROM chat_messages cm,(SELECT #maxvoteup:=0,#maxvotedown:=0,#minvoteup:=0,#minvotedown:=0,#maxvoteupid:=0,#maxvotedownid:=0)initial
ORDER BY cm.id ASC
)T
WHERE TIMESTAMPDIFF(SECOND,date_edited,'2016-04-21 22:20:25') < 10
OR id = #maxvoteupid
OR id = #maxvotedownid
ORDER BY id ASC;
sqlfiddle
I call it CRAZY because it is...if i was doing this. I would just run 3 separate queries
1 query to return one row with order by upvote DESC, downvote ASC, id DESC limit 1
1 query to return one row with order by downvote DESC, upvote ASC, id DESC limit 1
1 query to return one row that's within the last 10 seconds order by id DESC
this way it's much easier to maintain.

For grouping with mysql query

SELECT mf.fm_id,ema.asc_code as 'Xaxis', count(*) as 'Total'
from els_jobsheet_data as jd
join master_asc as ma on (jd.asc_id=ma.asc_id )
join els_master_asc_l3l4 as ema on jd.els_asc_code =ema.asc_code
join master_city as mc on mc.city_id=ma.city_id
join master_state as ms on ms.state_id=mc.state_id
join master_region as mr on mr.region_id=ms.region_id
join master_fso as mf on mf.fm_id=mr.fso_id
where jd.insert_time is not null AND jd.insert_time>='2015-12-01'
AND jd.insert_time<='2015-12-31'
group by Xaxis
order by Xaxis ASC
A query returned-
fm_id Xaxis Total
2 DOA 43
3 DSRO 12
1 TRC 12
9 3423 10
5 5455 11
2 2443 13
7 55AS 2
But I want to group it like
fm_id Xaxis Total
2 DOA 43
3 DSRO 12
1 TRC 12
9 Other 342
(whatever be its total)
i m newbie.Pls help..
Use a case expression instead of the raw data.
SELECT
max(mf.fm_id) as fm_id
, CASE
WHEN ema.asc_code IN ('DOA', 'DSRO', 'TRC') THEN ema.asc_code
ELSE 'Other'
END AS Xaxis
, COUNT(*) AS Total
FROM els_jobsheet_data AS jd
JOIN master_asc AS ma ON (jd.asc_id = ma.asc_id)
JOIN els_master_asc_l3l4 AS ema ON jd.els_asc_code = ema.asc_code
JOIN master_city AS mc ON mc.city_id = ma.city_id
JOIN master_state AS ms ON ms.state_id = mc.state_id
JOIN master_region AS mr ON mr.region_id = ms.region_id
JOIN master_fso AS mf ON mf.fm_id = mr.fso_id
WHERE jd.insert_time IS NOT NULL
AND jd.insert_time >= '2015-12-01'
AND jd.insert_time <= '2015-12-31'
GROUP BY
CASE
WHEN ema.asc_code IN ('DOA', 'DSRO', 'TRC') THEN ema.asc_code
ELSE 'Other'
END
ORDER BY
Xaxis ASC