I have 23 users in group 75(user_group).
Then I have table users_participated where row is set only if user participated ( sometimes it exists but is 0 ( not participate ) ).
Now I need to show each day for every user this month did he participate or not.
I can do it with php loop. But I was wondering if there is a way to do it only with single mysql query.
//output html table should look like y = yes n = no 1,2,3,5 are days in month
user | 1 | 2 | 3 | 4 | 5..
user1| y | n | y | n | n
user2| n | y | y | n | y
// user table
id | user | group
1 | user1 | 75
2 | user2 | 75
3 | user3 | 75
4 | user4 | 68
//participate table
user_id | participated | date_added
1 | 1 | 2014-03-29 11:03:00
2 | 0 | 2014-03-29 11:03:00
//sometimes it can be 0 AND sometimes if its null its not even in this table if u know what i mean.
How can I do this ?
A simple crosstab query can do that:
SELECT u.user,
max( if(day(p.date_added) = 1, p.participated, 0 ) ) day1,
max( if(day(p.date_added) = 2, p.participated, 0 ) ) day2,
..............
..............
..............
max( if(day(p.date_added) = 28, p.participated, 0 ) ) day28,
max( if(day(p.date_added) = 29, p.participated, 0 ) ) day29,
max( if(day(p.date_added) = 30, p.participated, 0 ) ) day30,
max( if(day(p.date_added) = 31, p.participated, 0 ) ) day31
FROM user u
JOIN participate p
ON u.id = p.user_id
WHERE p.date_added >= '2014-03-01'
AND p.date_added < '2014-04-01'
GROUP BY u.id
demo: http://sqlfiddle.com/#!9/cd31f/3
Related
I have a MySQL table like this;
recordID| netcall | sign | activity | netid
1 | group1 | wa1 | 1 | 20
2 | group2 | wa2 | 2 | 30
3 | group1 | wa2 | 1 | 20
4 | group2 | wa3 | 2 | 30
5 | group1 | wa1 | 1 | 40
6 | group3 | wa4 | 3 | 50
7 | group3 | wa4 | 3 | 50
8 | group1 | wa2 | 1 | 40
9 | group1 | wa1 | 1 | 40
10 | group2 | wa4 | 2 | 60
What I need from that is:
Netcall | count | activity | netid
Group1 | 3 | 1 | 40
Group2 | 2 | 2 | 30
Group3 | 2 | 3 | 50
I thought I could;
SELECT MAX(xx.mycount) AS MAXcount
FROM (SELECT COUNT(tt.sign) AS mycount ,tt.activity
FROM NetLog tt
WHERE ID <> 0
GROUP BY netcall) xx
But this only brings up the grand total not broken down by netcall. I don't see an example of this question but I'm sure there is one, I'm just asking it wrong.
Your example and desire output are too basic, you should try to expand so include more cases.
Right now you can get the desire output with:
SELECT `netcall`, COUNT(*) as `total`, MAX(`activity`) as `activity`
FROM t
GROUP BY `netcall`;
My guess is you can have different activities for group so you need multiples steps
Calculate the COUNT() for GROUP BY netcall, activity I call it q
Then see what is the MAX(total) for each netcall I call it p
Now you reuse q as o you have all the count, so just select the one with the max count.
SQL DEMO
SELECT o.`netcall`, o.total, o.`activity`
FROM (
SELECT `netcall`, COUNT(*) `total`, `activity`
FROM t
GROUP BY `netcall`, `activity`
) o
JOIN (
SELECT `netcall`, MAX(`total`) as `total`
FROM (
SELECT `netcall`, COUNT(*) `total`
FROM t
GROUP BY `netcall`, `activity`
) q
GROUP BY `netcall`
) p
ON o.`netcall` = p.`netcall`
AND o.`total` = p.`total`
With MySQL v8+ you can use cte and window function to simplify a little bit
with group_count as (
SELECT `netcall`, COUNT(*) as total, `activity`
FROM t
GROUP BY `netcall`, `activity`
), group_sort as (
SELECT `netcall`, total, `activity`,
RANK() OVER (PARTITION BY `netcall`, `activity` ORDER BY total DESC) as rnk
FROM group_count
)
SELECT *
FROM group_sort
WHERE rnk = 1
This question is asked (and answered) every day on SO; it even has its own chapter in the MySQL manual, but anyway...
SELECT a.netcall
, b.total
, a.activity
FROM netlog a
JOIN
( SELECT netcall
, MAX(record_id) record_id
, COUNT(*) total
FROM netlog
GROUP
BY netcall
) b
ON b.netcall = a.netcall
AND b.record_id = a.record_id
SELECT k.netcall, k.netID, MAX(k.logins) highest,
AVG(k.logins) average, netDate, activity
FROM
(SELECT netID, netcall, COUNT(*) logins, DATE(`logdate`) as netDate, activity
FROM NetLog
WHERE netID <> 0 AND status = 1
AND netcall <> '0' AND netcall <> ''
GROUP BY netcall, netID) k
GROUP BY netcall
ORDER BY highest DESC
Resulted in:
Net Call Highest Average Net ID Sub Net Of... ICS
214 309 Map Date Activity
MESN 65 41.5294 339 214 309 MAP 2017-09-03 MESN
W0KCN 34 14.9597 1 214 309 MAP 2016-03-15 KCNARES Weekly 2m Voice Net
W0ERH 31 31.0000 883 214 309 MAP 2018-10-12 Johnson Co. Radio Amateurs Club Meeting Net
KCABARC 29 22.3333 57 214 309 MAP 2016-10-10 KCA Blind Amateurs Weekly 2m Voice Net
....
I have a two tables:
case_map
case_id | creation_date
________|___________________
49 | 2013-04-30
51 | 2013-05-15
82 | 2014-05-23
109 | 2013-06-01
123 | 2013-07-23
case_legend
id | case_id | operation_number | operation_date | failure
___|_________|__________________|________________|________
1 | 49 | 105 | 2013-05-03 | 0
2 | 51 | 105 | 2013-05-28 | 0
3 | 51 | 110 | 2013-05-29 | 0
4 | 51 | 115 | 2013-06-02 | 1
5 | 51 | 110 | 2013-06-05 | 0
6 | 82 | 105 | 2013-05-28 | 0
7 | 82 | 110 | 2013-05-30 | 0
8 | 82 | 115 | 2013-06-01 | 0
9 | 82 | 120 | 2013-06-01 | 0
10 | 82 | 125 | 2013-06-02 | 0
11 | 109 | 105 | 2013-06-27 | 0
12 | 123 | 105 | 2013-07-27 | 0
13 | 123 | 110 | 2013-08-10 | 0
And I want to know how many cases was recieved and how many of these cases are on operation 105 and 125 ('on operation' = value of operation_number for row with max operation_date for this case_id) in a certain time interval, for example 'from May, 2013 to Jule, 2013', splited by mounth.
For these purposes, I made the following query:
SELECT
`recieved_cases`.`abbreviated_date`,
`recieved_cases`.`recieved_count`,
`operation_105`.`105_count`,
`operation_125`.`125_count`
FROM (
SELECT DATE_FORMAT( `creation_date`, '%Y-%m' ) AS `abbreviated_date`, COUNT( `case_id` ) AS `recieved_count`
FROM `case_map`
WHERE `creation_date` BETWEEN '2013-05-01' AND '2013-07-31'
GROUP BY `abbreviated_date`
) AS `recieved_cases`
LEFT JOIN (
SELECT DATE_FORMAT( `t1`.`operation_date`, '%Y-%m' ) AS `abbreviated_date`, COUNT( `t1`.`operation_number` ) AS `105_count`
FROM `case_legend` AS `t1`
WHERE `t1`.`id` = (
SELECT `t2`.`id`
FROM `case_legend` AS `t2`
WHERE `t2`.`case_id` = `t1`.`case_id`
ORDER BY `t2`.`operation_date` DESC, `t2`.`id` DESC
LIMIT 1
)
AND `operation_number` = 105
GROUP BY `abbreviated_date`
) AS `operation_105`
ON `recieved_cases`.`abbreviated_date` = `operation_105`.`abbreviated_date`
LEFT JOIN (
SELECT DATE_FORMAT( `t1`.`operation_date`, '%Y-%m' ) AS `abbreviated_date`, COUNT( `t1`.`operation_number` ) AS `125_count`
FROM `case_legend` AS `t1`
WHERE `t1`.`id` = (
SELECT `t2`.`id`
FROM `case_legend` AS `t2`
WHERE `t2`.`case_id` = `t1`.`case_id`
ORDER BY `t2`.`operation_date` DESC, `t2`.`id` DESC
LIMIT 1
)
AND `operation_number` = 125
GROUP BY `abbreviated_date`
) AS `operation_125`
ON `recieved_cases`.`abbreviated_date` = `operation_125`.`abbreviated_date`
ORDER BY `recieved_cases`.`abbreviated_date`
My problem is that such a request takes into account also cases with creation_date not in a specified time interval. Ie case, which has the last operation in the specified interval, but was created earlier - is taken into account, and it should not be. How can I fix this query?
Desired result for provided example is:
abbreviated_date | recieved_count | 105_count | 125_count
_________________|________________|___________|__________
2013-05 | 2 | 0 | 0
2013-06 | 1 | 1 | 1
2013-07 | 1 | 0 | 0
Can a temporary table helps me here? I mean if I first create table like case_legend with creation_date field. I think on this one for the last hour, but not sure how to do it.
P.S. Also, if my query is bad and you can give me an advise how to optimize it - I would be grateful.
This may be what you want:
select year(cm.creation_date), month(cm.creation_date),
count(distinct case when cl.operation_number = 105 then case_id end) as op105,
count(distinct case when cl.operation_number = 125 then case_id end) as op125
from case_map cm join
case_legend cl
on cm.case_id = cl.case_id
group by year(cm.creation_date), month(cm.creation_date)
order by 1, 2;
If not, you can start with the most recent date for each of the operations:
select cm.*,
max(case when cl.operation_number = 105 then operation_date end) as op105,
max(case when cl.operation_number = 125 then operation_date end) as op125
from case_map cm join
case_legend cl
on cm.case_id = cl.case_id
group by cm.case_id;
And then work from there.
EDIT:
Now that you supplied the desired results, the query is not too difficult:
select date_format(cm.creation_date, '%Y-%m' ) as yyyymm,
sum(cl.opeartion_number = 105) as op105,
sum(cl.opeartion_number = 125) as op125
from case_map cm join
case_legend cl
on cm.case_id = cl.case_id
where not exists (select 1
from case_legend cl2
where cl2.case_id = cl.case_id and
cl2.operation_date > cl.operation_date
)
group by date_format(cm.creation_date, '%Y-%m')
order by 1;
So the answer is: You don't need temporary tables.
Here's this fiddle:
http://sqlfiddle.com/#!2/8673a3/9
It gives you the same results but in a different format perhaps, than what you prefer.
select
DATE_FORMAT( operation_date, '%Y-%m' ) as `Date`,
count(cl.case_id), cl.operation_number,
t.count
from
case_legend cl
left join case_map cm
on cl.case_id = cm.case_id
left join (
select
DATE_FORMAT( cl.operation_date, '%Y-%m' ) as `Date`, count(cl.case_id) as `count`, 'All' as operation_number
from
case_legend cl
left join case_map cm
on cl.case_id = cm.case_id
where operation_date BETWEEN '2013-05-01' AND '2013-07-31'
GROUP BY DATE_FORMAT( operation_date, '%Y-%m' )
) t
on t.Date = DATE_FORMAT( operation_date, '%Y-%m' )
where cl.operation_number in (105, 125)
and operation_date BETWEEN '2013-05-01' AND '2013-07-31'
GROUP BY DATE_FORMAT( operation_date, '%Y-%m' ), cl.operation_number
;
I not mysql expert and I need help to make count query, I need merge sum of count from id 5 and 11 to one count number = 286 and give platform name as GCS in this case.
SELECT DISTINCT (p.id) AS id, (p.name) AS platform,
IFNULL(count(e.id), 0) AS count
FROM event e, lu_platform p
WHERE e.platform_id = p.id
AND p.id NOT IN ( 10, 15, 17, 18 )
AND e.sourcetype_id = 1
AND e.event_datetime BETWEEN '2013-11-4'
AND '2013-11-10' AND e.sender_id NOT IN ( 759, 73 )
GROUP BY p.id ORDER BY id;
+----+---------------------------+-------+
| id | platform | count |
+----+---------------------------+-------+
| 3 | GGG | 414 |
| 4 | KIKI | 156 |
| 5 | KJC | 284 |
| 6 | LOLO | 4 |
| 7 | MOD | 1147 |
| 8 | MARKT | 1049 |
| 11 | GCS | 2 |
| 12 | POLAR | 30 |
| 14 | GUAE | 145 |
+----+---------------------------+-------+
One possible way to do it - use a subquery, a sum, and IF function, or a case expression CASE WHEN THEN:
SELECT sum( case when id in ( 5, 11 ) then count else 0 end ) as count_5_11,
sum( if( id in ( 3, 4 ), count, 0 ) ) As count_3_4
FROM (
-- your query goes here
SELECT DISTINCT (p.id) AS id, (p.name) AS platform,
IFNULL(count(e.id), 0) AS count
....
....
....
....
....
) AS some_alias
Try to use sub-query
SELECT SUM(count) as count, `GCG` as platform
FROM
(
SELECT DISTINCT (p.id) AS id, (p.name) AS platform,
IFNULL(count(e.id), 0) AS count
FROM event e, lu_platform p
WHERE e.platform_id = p.id
AND p.id NOT IN ( 10, 15, 17, 18 )
AND e.sourcetype_id = 1
AND e.event_datetime BETWEEN '2013-11-4'
AND '2013-11-10' AND e.sender_id NOT IN ( 759, 73 )
GROUP BY p.id ORDER BY id;
) T
WHERE id IN (5,11)
Thank you for reply.
In the both above answers I get only one results instead of list. I think the best way is do this in application as was mentioned by sarwar026.
I noticed also that ISNULL(count(e.id), 0) is not working as I expected, platforms without records not returning 0, they are skipped.
i have a problem with some querys in php and mysql:
I have 2 different tables with one field in common:
table 1
id | hits | num_g | cats | usr_id |active
1 | 10 | 11 | 1 | 53 | 1
2 | 13 | 16 | 3 | 53 | 1
1 | 10 | 22 | 1 | 22 | 1
1 | 10 | 21 | 3 | 22 | 1
1 | 2 | 6 | 2 | 11 | 1
1 | 11 | 1 | 1 | 11 | 1
table 2
id | usr_id | points
1 | 53 | 300
Now i use this statement to sum just the total from the table 1 every id count + 1 too
SELECT usr_id, COUNT( id ) + SUM( num_g + hits ) AS tot_h FROM table1 WHERE usr_id!='0' GROUP BY usr_id ASC LIMIT 0 , 15
and i get the total for each usr_id
usr_id| tot_h |
53 | 50
22 | 63
11 | 20
until here all is ok, now i have a second table with extra points (table2)
I try this:
SELECT usr_id, COUNT( id ) + SUM( num_g + hits ) + (SELECT points FROM table2 WHERE usr_id != '0' ) AS tot_h FROM table1 WHERE usr_id != '0' GROUP BY usr_id ASC LIMIT 0 , 15
but it seems to sum the 300 extra points to all users:
usr_id| tot_h |
53 | 350
22 | 363
11 | 320
Now how i can get the total like the first try but + the secon table in one statement? because now i have just one entry in the second table but i can be more there.
thanks for all the help.
hi thomas thanks for your reply, i think is in the right direction, but i'm getting weirds results, like
usr_id | tot_h
22 | NULL <== i think the null its because that usr_id as no value in the table2
53 | 1033
Its like the second user is getting all the the values. then i try this one:
SELECT table1.usr_id, COUNT( table1.id ) + SUM( table1.num_g + table1.hits + table2.points ) AS tot_h
FROM table1
LEFT JOIN table2 ON table2.usr_id = table1.usr_id
WHERE table1.usr_id != '0'
AND table2.usr_id = table1.usr_id
GROUP BY table1.usr_id ASC
Same result i just get the sum of all values and not by each user, i need something like this result:
usr_id | tot_h
53 | 53 <==== plus 300 points on table1
22 | 56 <==== plus 100 points on table2
/////////the result i need ////////////
usr_id | tot_h
53 | 353 <==== plus 300 points on table2
22 | 156 <==== plus 100 points on table2
I think the structure need to be something like this
Pseudo statements ;)
from table1 count all id to get the number of record where the usr_id are then sum hits + num_g and from table2 select the extra points where the usr_id are the same as table1 and get the result:
usr_id | tot_h
53 | 353
22 | 156
There is nothing in your subquery which calculates extra points to correlate it to the outer Table1. So, one solution is to add that correlation:
SELECT usr_id
, COUNT( id ) + SUM( num_g + hits )
+ (SELECT points
FROM table2
WHERE table2.usr_id = table1.usr_id ) AS tot_h
FROM table1
WHERE usr_id != '0'
GROUP BY usr_id ASC
LIMIT 0 , 15
Another solution would be to simply join to it directly:
SELECT table1.usr_id
, COUNT( table1.id )
+ SUM( table1.num_g + table1.hits + table2.points )
AS tot_h
FROM table1
Left Join table2
On table2.usr_id = table1.usr_id
WHERE table1.usr_id != '0'
GROUP BY table1.usr_id ASC
LIMIT 0 , 15
i think get the solution, i dont know if its the best but it works for me, if you know a way to optimize this i really apreciate it.
SELECT usr_id , COUNT( id ) + SUM( num_g + hits )as sumtot ,
(SELECT points FROM table2 WHERE usr_id = table1.usr_id ) AS tot_h
FROM table1
WHERE usr_id != '0'
GROUP BY usr_id ASC
with this i get something like this
usr_id |sumtot | tot_h
5 |557 | NULL
53 |2217 | 300
So then i just sum the result and show it in a while loop.
<?php
//some mysql here
//then the while loop
// and then the final sum
$final_result=$r_rank['tot_h']+$r_rank['sumtot'];
?>
Thanks a lot for your help thomas :)
I have two tables
user_raters:
| id(int) | to_id(int) | value(int) | created_at(datetime)
|1 | 2 | 1 | 2009-03-01 00:00:00
EDIT: I changed the user_rater_id. history_user_raters.user_rater_id is related to user_raters.id
history_user_raters:
| id(int) | user_rater_id(int) | value(int) | created_at(datetime)
| 1 | 1 | 1 | 2009-03-02 00:00:00
| 2 | 1 | 1 | 2009-03-02 00:00:00
| 3 | 1 | -1 | 2009-03-02 00:00:00
| 4 | 1 | 1 | 2009-03-03 00:00:00
| 5 | 1 | -1 | 2009-03-03 00:00:00
| 6 | 1 | -1 | 2009-03-03 00:00:00
| 7 | 1 | -1 | 2009-03-03 00:00:00
I want to count the sum of the values from history_user_raters as it relates to the to_id from user_raters. The result from the query should be:
| year | month | day | total | down | up
| 2009 | 3 | 2 | 1 | 1 | 2
| 2009 | 3 | 3 | -2 | 3 | 1
I have a query that is close, but it is not counting the up and down correctly. The total is right. Can some one help me write the query or new query that calculates correct up and down?
My current query:
SELECT
YEAR(history.created_at) AS `year`,
MONTH(history.created_at) AS `month`,
DAY(history.created_at) AS `day`,
SUM(history.value) as `total`,
(SELECT
abs(SUM(historydown.value))
FROM `user_raters` as raterdown
INNER JOIN `history_user_raters` AS historydown
WHERE raterdown.to_id = 2
AND historydown.value = -1
AND date(historydown.created_at)
GROUP BY history.created_at) as down,
(SELECT SUM(historyup.value)
FROM `user_raters` as raterup
INNER JOIN `history_user_raters` AS historyup
WHERE raterup.to_id = 2
AND historyup.value = 1
AND date(history.created_at)
GROUP BY raterup.to_id) as up
FROM `user_raters`
INNER JOIN history_user_raters AS history ON user_raters.id = history.user_rater_id
WHERE (user_raters.to_id = 2)
GROUP BY DATE(history.created_at)
I might see it too simply (and sorry I can't test with data at the moment), but I'm guessing the following trick with two CASE statements would do just what is needed
SELECT
YEAR(history.created_at) AS year,
MONTH(history.created_at) AS month,
DAY(history.created_at) AS day,
SUM(history.value) as total,
SUM(CASE WHEN history.value < 0 THEN history.value ELSE 0 END) as down,
SUM(CASE WHEN history.value > 0 THEN history.value ELSE 0 END) as up
FROM `user_raters`
INNER JOIN `history_user_raters` AS history
ON user_raters.id = history.user_rater_id
WHERE (user_raters.to_id = 1) -- or some other condition...
GROUP BY DATE(history.created_at)
EDIT: #OMG Ponies deleted his answer. This response make no sense now, but I am not going to delete my answer, because I think it is silly.
#OMG ponies
Your query runs, but it returns no results. I had to adjust it a bit to add the to_id in the main queries where clause
SELECT
YEAR( t.created_at ) AS `year` ,
MONTH( t.created_at ) AS `month` ,
DAY( t.created_at ) AS `day` ,
SUM( t.value ) AS `total` ,
MAX( COALESCE( x.sum_down, 0 ) ) AS down,
MAX( COALESCE( y.sum_up, 0 ) ) AS up
FROM history_user_raters AS t
JOIN user_raters AS ur ON ur.to_id = t.user_rater_id
LEFT JOIN (
SELECT hur.user_rater_id,
SUM( hur.value ) AS sum_down
FROM history_user_raters AS hur
WHERE hur.value = -1
GROUP BY hur.user_rater_id
) AS x ON x.user_rater_id = t.user_rater_id
LEFT JOIN (
SELECT hur.user_rater_id,
SUM( hur.value ) AS sum_up
FROM history_user_raters AS hur
WHERE hur.value =1
GROUP BY hur.user_rater_id
) AS y ON y.user_rater_id = t.user_rater_id
WHERE ur.to_id =1
GROUP BY YEAR( t.created_at ) , MONTH( t.created_at ) , DAY( t.created_at )