Arithmetic in MySQL for count of actions in a minute - mysql

I have this table in MySQL:
id | Action | DateTime | Time(ms)
-----+------------------------------+----------------------------+-------------
1 | Player1_rightKeyPress_Start | 2014-10-01 18:51:17.795000 | 7322
2 | Player1_shootKeyPress_Start | 2014-10-01 18:51:17.971000 | 7498
3 | Player1_rightKeyPress_Start | 2014-10-01 18:51:18.035000 | 7562
4 | Player2_leftKeyPress_Start | 2014-10-01 18:51:18.126000 | 7653
5 | Player1_shootKeyPress_Start | 2014-10-01 18:51:18.214000 | 7741
6 | Player1_rightKeyPress_Start | 2014-10-01 18:51:18.305000 | 7832
7 | Player2_leftKeyPress_Start | 2014-10-01 18:51:18.369000 | 7896
8 | Player1_shootKeyPress_Start | 2014-10-01 18:51:18.374000 | 7901
9 | Player1_rightKeyPress_Start | 2014-10-01 18:51:18.467000 | 7994
10 | Player1_shootKeyPress_Start | 2014-10-01 18:51:18.580000 | 8107
11 | Player1_rightKeyPress_Start | 2014-10-01 18:51:18.676000 | 8203
12 | Player1_shootKeyPress_Start | 2014-10-01 18:51:18.812000 | 8339
13 | Player1_rightKeyPress_Start | 2014-10-01 18:51:18.899000 | 8426
14 | Player1_shootKeyPress_Start | 2014-10-01 18:51:19.050000 | 8577
15 | Player1_rightKeyPress_Start | 2014-10-01 18:51:19.123000 | 8650
This is just a part of the table in the database. What I want to do is to count the number of times Player1_rightKeyPress_Start, Player1_shootKeyPress_Start and Player2_leftKeyPress_Start occurred in every 10,000second. The time runs up to 600,000 miliseconds. I did not bother to include all of it because it is really large.

You probably could do something along these lines: convert to seconds, divide by 10 to get the 10 second intervals, and then apply the group by:
SELECT Action, FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(DateTime)/10)), COUNT(*)
FROM myTable
GROUP BY Action, FLOOR(UNIX_TIMESTAMP(DateTime)/10)
Check the mysql docs for the time functions.

I'm not sure if I understand your question right, but the following sql should count the occurrence of Player1_rightKeyPress_Start in the entire table (swap [TABLENAME]):
SELECT COUNT(*) FROM [TABLENAME] WHERE Action = 'Player1_rightKeyPress_Start';
Paste the result of desc [TABLENAME] and SELECT * FROM [TABLENAME] LIMIT 10; would help. And add your desired result as #Sean said should also help.

Related

MySQL - select average of column A for first N entries from column B

I have a ratings table, where each user can add one rating a day. But each user might miss several days between ratings.
I'd like to get the average rating for each user_id's first 7 entries of created_at.
My table:
mysql> desc entries;
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| rating | tinyint(4) | NO | | NULL | |
| user_id | int(10) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
+------------+------------------+------+-----+---------+----------------+
Ideally I'd just get something like:
+------------+------------------+
| day | average_rating |
+------------+------------------+
| 1 | 2.53 |
+------------+------------------+
| 2 | 4.30 |
+------------+------------------+
| 3 | 3.67 |
+------------+------------------+
| 4 | 5.50 |
+------------+------------------+
| 5 | 7.23 |
+------------+------------------+
| 6 | 6.98 |
+------------+------------------+
| 7 | 7.22 |
+------------+------------------+
The closest I've been able to get is:
SELECT rating, user_id, created_at FROM entries ORDER BY user_id asc, created at desc
Which isn't very close at all...
Is it even possible? Will the performance be terrible? It's something that would need to run every time a web page is loaded, so would it be better to just run this once a day and save the results? (to another table!?)
edit - second attempt
Working towards a solution, I think this would get the rating for each user's first day:
select rating from entries where user_id in
(select user_id from entries order by created_at limit 1);
But I get:
ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
So now I'm going to play around with JOIN to see if that helps.
edit - third attempt, getting closer
I found this stackoverflow post, which is closer to what I want.
select e1.* from entries e1 left join entries e2
on (e1.user_id = e2.user_id and e1.created_at > e2.created_at)
where e2.id is null;
It gets the rating for the first day for each user.
Next step is to work out how to get days 2 to 7. I can't use 1.created_at > e2.created_at for that, so I'm really confused now.
edit - fourth attempt
Okay, I think it's not possible. Once I worked out how to turn off 'full group by' mode, I realised I'll probably need to use a subquery with limit <user_id>, <day_num>, for which I get:
ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
My current method is to just get the entire table, and use PHP to calculate the average for each day.
If I understand correctly you want to take the last 7 ratings the user gave, ordered by the date they gave the rating. The last 7 ratings of one user may fall on different days to another user, however they will be averaged together regardless of date.
First we need to order the data by user and date and give each user their own incrementing row count. I do this by adding two variables, one for the last user id and one for the row number:
select e.created_at,
e.rating,
if(#lastUser=user_id,#row := #row+1, #row:=1) as row,
#lastUser:= e.user_id as user_id
from entries e,
( select #row := 0, #lastUser := 0 ) vars
order by e.user_id asc,
e.created_at desc;
If the previous user_id is different we reset the row counter to 1. The result from this is:
+---------------------+--------+------+---------+
| created_at | rating | row | user_id |
+---------------------+--------+------+---------+
| 2017-01-10 00:00:00 | 1 | 1 | 1 |
| 2017-01-09 00:00:00 | 1 | 2 | 1 |
| 2017-01-08 00:00:00 | 1 | 3 | 1 |
| 2017-01-07 00:00:00 | 1 | 4 | 1 |
| 2017-01-06 00:00:00 | 1 | 5 | 1 |
| 2017-01-05 00:00:00 | 1 | 6 | 1 |
| 2017-01-04 00:00:00 | 1 | 7 | 1 |
| 2017-01-03 00:00:00 | 1 | 8 | 1 |
| 2017-01-02 00:00:00 | 1 | 9 | 1 |
| 2017-01-01 00:00:00 | 1 | 10 | 1 |
| 2017-01-13 00:00:00 | 1 | 1 | 2 |
| 2017-01-11 00:00:00 | 1 | 2 | 2 |
| 2017-01-09 00:00:00 | 1 | 3 | 2 |
| 2017-01-07 00:00:00 | 1 | 4 | 2 |
| 2017-01-05 00:00:00 | 1 | 5 | 2 |
| 2017-01-03 00:00:00 | 1 | 6 | 2 |
| 2017-01-01 00:00:00 | 1 | 7 | 2 |
| 2017-01-13 00:00:00 | 1 | 1 | 3 |
| 2017-01-01 00:00:00 | 1 | 2 | 3 |
| 2017-01-03 00:00:00 | 1 | 1 | 4 |
| 2017-01-01 00:00:00 | 1 | 2 | 4 |
| 2017-01-02 00:00:00 | 1 | 1 | 5 |
+---------------------+--------+------+---------+
We now simply wrap this in another statement to select the avg where the row number is less than or equal to seven.
select e1.row day, avg(e1.rating) avg
from (
select e.created_at,
e.rating,
if(#lastUser=user_id,#row := #row+1, #row:=1) as row,
#lastUser:= e.user_id as user_id
from entries e,
( select #row := 0, #lastUser := 0 ) vars
order by e.user_id asc,
e.created_at desc) e1
where e1.row <=7
group by e1.row;
This outputs:
+------+--------+
| day | avg |
+------+--------+
| 1 | 1.0000 |
| 2 | 1.0000 |
| 3 | 1.0000 |
| 4 | 1.0000 |
| 5 | 1.0000 |
| 6 | 1.0000 |
| 7 | 1.0000 |
+------+--------+

Group by hour and date

I hate to ask a question here, as I know it's been done (slightly), however my problem is slightly different because of the field formats. I've tried a bunch of things on joins and hour selections and others, and I'm stuck. Would love a quick hand.
I've got a MySQL table like so:
CREATE TABLE `VAT` (
`VATid` int(11) NOT NULL AUTO_INCREMENT,
`VATDate` date DEFAULT NULL,
`VATTime` varchar(10) DEFAULT NULL,
`VATPledgeAmount` float DEFAULT NULL,
PRIMARY KEY (`VATid`),
UNIQUE KEY `VATid_UNIQUE` (`VATid`)
) ENGINE=MyISAM AUTO_INCREMENT=6531 DEFAULT CHARSET=latin1;
The problem that is that the VATDate fields have dates in the following format YYYY-MM-DD and the VATTime fields are a HHMM with leading zeros, as shown in the following table with some example data.
Sample Table Data:
VATid | VATDate | VATTime | VATPledgeAmount |
--------------------------------------------------
1 | 2016-06-30 | 0730 | 100 |
2 | 2016-06-30 | 0733 | 20 |
3 | 2016-06-30 | 0840 | 70 |
4 | 2016-06-30 | 0943 | 100 |
5 | 2016-06-30 | 0730 | 50 |
6 | 2016-07-01 | 2113 | 50 |
7 | 2016-07-01 | 2302 | 300 |
8 | 2016-07-02 | 0416 | 10 |
9 | 2016-07-02 | 0417 | 10 |
10 | 2016-07-02 | 0418 | 10 |
What I want to do is have the MySQL server do the calculations for me, so that when the data comes out the dates are still shown, but the total values from the PledgeAmount for each hour are summed up and grouped.
Counts | g_VATDate | g_VATTime | Total_VATPledgeAmount |
--------------------------------------------------
2 | 2016-06-30 | 0700 | 120 |
1 | 2016-06-30 | 0800 | 70 |
1 | 2016-06-30 | 0900 | 100 |
1 | 2016-07-01 | 2100 | 50 |
1 | 2016-07-01 | 2300 | 300 |
3 | 2016-07-02 | 0400 | 30 |
I hope this makes sense. I'm planning on using this for a JS graph, but as I don't need or want the individual pledges and their amount values, I just want the amounts and totals for each hour.
You can use concat(left(VATTime, 2), '00') to get the hour:
select count(VATid) counts, VATDate g_VATDate,
concat(left(VATTime, 2), '00') g_VATTime,
sum(VATPledgeAmount) Total_VATPledgeAmount
from VAT
group by g_VATDate, g_VATTime;

How to get sum for different entry in mysql

I have table in mysql like
| service_code | charges | caller_number | duration | minutes |
+--------------+---------+---------------+----------+---------+
| 10 | 15 | 8281490235 | 00:00:00 | 1.0000 |
| 11 | 12 | 9961621709 | 00:00:00 | 0.0000 |
| 10 | 15 | 8281490235 | 01:00:44 | 60.7333 |
| 11 | 2 | 9744944316 | 01:00:44 | 60.7333 |
+--------------+---------+---------------+----------+---------+
from this table I want to get charges*minutes for each separate caller_number.
I have done like this
SELECT sum(charges*minutes) as cost from t8_m4_bill groupby caller_number
but I am not getting expected output. Please help?
SELECT caller_number,sum(charges*minutes) as cost
from t8_m4_bill
group by caller_number
order by caller_number

Listing results with unique column

I want to list top 6 race records with unique holder only. I mean a holder gets in the list shouldn't be listed with his another record. I currently use the query below to list top 6 times.
mysql> select * from racerecords order by record_time asc, date asc;
+----+---------+------------+-------------+---------------------+----------+
| id | race_id | holder | record_time | date | position |
+----+---------+------------+-------------+---------------------+----------+
| 2 | 10 | Stav | 15 | 2014-08-11 19:43:49 | 1 |
| 1 | 10 | Jennifer | 15 | 2014-08-13 19:43:19 | 1 |
| 4 | 10 | Jennifer | 16 | 2014-08-02 19:44:27 | 1 |
| 5 | 10 | Osman | 17 | 2014-08-04 19:44:57 | 1 |
| 7 | 10 | Gokhan | 18 | 2014-08-15 19:45:37 | 1 |
| 3 | 10 | MotherLode | 25 | 2014-08-01 19:44:11 | 1 |
+----+---------+------------+-------------+---------------------+----------+
6 rows in set (0.00 sec)
As you can see the holder "Jennifer" is listed twice. I want mySQL to skip her after she got in the list. The result I want to be generated is:
+----+---------+------------+-------------+---------------------+----------+
| id | race_id | holder | record_time | date | position |
+----+---------+------------+-------------+---------------------+----------+
| 2 | 10 | Stav | 15 | 2014-08-11 19:43:49 | 1 |
| 1 | 10 | Jennifer | 15 | 2014-08-13 19:43:19 | 1 |
| 5 | 10 | Osman | 17 | 2014-08-04 19:44:57 | 1 |
| 7 | 10 | Gokhan | 18 | 2014-08-15 19:45:37 | 1 |
| 3 | 10 | MotherLode | 25 | 2014-08-01 19:44:11 | 1 |
+----+---------+------------+-------------+---------------------+----------+
I tried everything. GROUP BY holder generates wrong results. It gets the very first record of the holder, even though is not the best. In this table it generates an output like above because id:1 is the first record I inserted for Jennifer.
How can I generate output a result like above?
Desired result can be achieved through this query but it performance intensive. I have reproduced the result in SQLFilddle http://sqlfiddle.com/#!2/f8ee7/3
select * from racerecords
where
(HOLDER, RECORD_TIME) in (
select HOLDER,min(RECORD_TIME) from racerecords
group by HOLDER)
Seems you have missed to include the Where clause in the sub-query. Try this
select * from racerecords
where
(HOLDER, RECORD_TIME) in (
select HOLDER,min(RECORD_TIME) from racerecords where race_id =17
group by HOLDER )
And race_id =17
Order by RECORD_TIME
you should use distinct clause
SELECT DISTINCT column_name,column_name
FROM table_name;
looks this http://www.w3schools.com/sql/sql_distinct.asp

Update records with sequential number number based on date field

I have a database full of about 500 records that work in the following way
id | group | date | team1 | team2
I want to add a new field "matchid", and fill it in with a number 1 - 8 per group. So the record set would look like
1 | 2 | 2014-03-09 15:00:00 | j1 | j2
2 | 2 | 2014-03-09 16:30:00 | j3 | j4
3 | 2 | 2014-03-10 15:00:00 | j5 | j6
4 | 2 | 2014-03-10 16:30:00 | j7 | j8
5 | 2 | 2014-03-11 15:00:00 | j9 | j10
6 | 2 | 2014-03-11 16:30:00 | j11 | j12
7 | 2 | 2014-03-12 15:00:00 | j13 | j14
8 | 2 | 2014-03-12 16:30:00 | j15 | j16
9 | 3 | 2014-03-13 15:00:00 | j1 | j2
10 | 3 | 2014-03-14 16:30:00 | j3 | j4
11 | 3 | 2014-03-15 15:00:00 | j5 | j6
12 | 3 | 2014-03-16 16:30:00 | j7 | j8
13 | 3 | 2014-03-17 15:00:00 | j9 | j10
14 | 3 | 2014-03-18 16:30:00 | j11 | j12
15 | 3 | 2014-03-19 15:00:00 | j13 | j14
16 | 3 | 2014-03-20 16:30:00 | j15 | j16
This then goes on and on, so this happens weekly, groups get together on sequential times, usually 2 groups per day, so think of this as like a round like in sporting events.
What I need to do is get the new ID which will be something like
01
02
..
and so on to 08.
What I need to do is look at the date for the group and rank everything in order then update the matchid field with the sequential number.
The reason this needs to be done is that the managers have added a new matchid which relates to the game per match per group.
I am looking for a way to programatically do this within SQL so that I dont have to manually update every record.
I ended up doing this programatically in PHP and mysql.
I itereated through each "group" and tested the date values to order them into an array. once i had them ordered my date in the array, I was able to easily add the numbers sequentially.