I have multiple Raspberry Pi's collecting wifi beacons from mobile devices and save them in a mySQL DB. I have created a view in the DB. Each entry in the DB has the mobile device mac address, the pi id, rssi, location and a timestamp
I have created a view from multiple tables that looks like this.
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| pi_id | varchar(64) | NO | | NULL | |
| name | varchar(127) | NO | | NULL | |
| location | varchar(255) | NO | | NULL | |
| mac_id | varchar(200) | NO | | NULL | |
| rssi | int(11) | NO | | NULL | |
| datetime | datetime | NO | | NULL | |
+----------+--------------+------+-----+---------+-------+
For each Pi/location I want to count how many packets/beacons were seen during each 5 minute interval. I have been trying something like this.
SELECT datetime , location, count(*)
FROM packet_locations
GROUP BY DATE(DATE_SUB(datetime, INTERVAL 5 MINUTE)), location;
I want output like this:
+---------------------+----------+----------+
| datetime | location | count(*) |
+---------------------+----------+----------+
| 2016-01-26 00:00:00 | Pi1 | 44 |
| 2016-01-26 00:00:00 | Pi2 | 66 |
| 2016-01-26 00:05:00 | Pi1 | 100 |
| 2016-01-26 00:05:00 | Pi2 | 101 |
| 2016-01-26 00:10:00 | Pi1 | 128 |
| 2016-01-26 00:10:00 | Pi2 | 128 |
+---------------------+----------+----------+
SELECT concat( date_format(datetime,'%Y-%m-%d %k:')
, lpad(floor(minute(datetime)/5)*5,2,'0')
, ':00'
) datetime
, location
, count(1)
FROM packet_locations
GROUP BY date(datetime)
, hour(datetime)
, floor(minute(datetime)/5)
, location
Related
I have table which stores lecturers' available dates for lectures. Structure goes something like this:
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| lecturer_id | int(11) | NO | | NULL | |
| kraj_id | varchar(500) | YES | | NULL | |
| okres_id | varchar(500) | YES | | NULL | |
| lecture_date | datetime | NO | | NULL | |
| date_created | datetime | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
There can be rows with duplicate lecture_date.
When this happens I need to select the oldest row according to date_created. Have not solved it yet.
EDIT:
sample data:
+----+-------------+---------+---------------------------------------------------+---------------------+---------------------+
| id | lecturer_id | kraj_id | okres_id | lecture_date | date_created |
+----+-------------+---------+---------------------------------------------------+---------------------+---------------------+
| 36 | 38 | 1,4,12 | 1,2,3,4,5,6,7,18,19,20,21,22,72,73,74,75,76,77,78 | 2017-12-29 00:00:00 | 2017-12-16 16:20:38 |
| 37 | 38 | 1,4,12 | 1,2,3,4,5,6,7,18,19,20,21,22,72,73,74,75,76,77,78 | 2017-12-30 00:00:00 | 2017-12-16 16:20:40 |
| 38 | 38 | 1,4,12 | 1,2,3,4,5,6,7,18,19,20,21,22,72,73,74,75,76,77,78 | 2017-12-31 00:00:00 | 2017-12-16 16:20:42 |
| 39 | 41 | 7,12 | 33,34,35,36,37,72,73,74,75,76,77,78 | 2017-12-29 00:00:00 | 2017-12-16 16:21:15 |
| 40 | 41 | 7,12 | 33,34,35,36,37,72,73,74,75,76,77,78 | 2017-12-30 00:00:00 | 2017-12-16 16:21:17 |
| 41 | 41 | 7,12 | 33,34,35,36,37,72,73,74,75,76,77,78 | 2017-12-31 00:00:00 | 2017-12-16 16:21:20 |
+----+-------------+---------+---------------------------------------------------+---------------------+---------------------+
kraj_id and okres_id are ids of regions which are covered by lecturer. I am selecting rows by lecturer_id (for example: WHERE lecturer_id IN (38, 41)). If two or more lecturers cover the same regions there is chance that there will be duplicity in lecture_date. In that case I need to select the oldest according to date_created. In above example that would mean selecting rows with id 36, 37, 38.
I found this and it worked for me.
I had to make some changes to the query and this is the final version:
SELECT
id,
lecture_date,
lecturer_id,
date_created
FROM lecturer_has_dates
WHERE date_created IN (
SELECT MIN(date_created)
FROM lecturer_has_dates
GROUP BY lecture_date
)
AND lecture_date >= NOW()
AND lecturer_id IN (38, 41)
ORDER BY lecture_date DESC;
Thanks for all your suggestions!
I've got a table in MySQL:
+-----------------+-------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------------------+-------+
| period_duration | datetime | NO | PRI | 0000-00-00 00:00:00 | |
| duration | varchar(6) | YES | | NULL | |
| sample | varchar(2) | YES | | NULL | |
| corner | varchar(10) | YES | | NULL | |
| country | varchar(60) | NO | PRI | | |
| roaming_partner | varchar(60) | NO | PRI | | |
| pdp_in_total | int(8) | YES | | NULL | |
| pdp_in_ok | int(8) | YES | | NULL | |
| pdp_in_not_ok | int(8) | YES | | NULL | |
| pdp_in_ok_rate | int(8) | YES | | NULL | |
+-----------------+-------------+------+-----+---------------------+-------+
This table has new insertions hourly, that makes many different period_duration per roaming_partner:
+---------------------+----------+--------+----------+---------+-----------------------+--------------+-----------+---------------+----------------+
| period_duration | duration | sample | corner | country | roaming_partner | pdp_in_total | pdp_in_ok | pdp_in_not_ok | pdp_in_ok_rate |
+---------------------+----------+--------+----------+---------+-----------------------+--------------+-----------+---------------+----------------+
| 2014-12-16 14:00:00 | 3600 | 1 | GPRS_OUT | USA | Operator1 | 796 | 787 | 9 | 99 |
| 2014-12-16 15:00:00 | 3600 | 1 | GPRS_OUT | USA | Operator1 | 1748 | 1706 | 42 | 98 |
| 2014-12-16 16:00:00 | 3600 | 1 | GPRS_OUT | USA | Operator1 | 7 | 7 | 0 | 100 |
"ok_rate" is a percentage rate.
I need to create a SELECT that will show every single country, roaming_partner and pdp_in_ok_rate from the last 24 insertions, with the average pdp_in_ok_rate% from these insertions.
It is like i wanted that my SQL query say:
"This is the average pdp_in_ok_rate in the last 24 insertions for every operator on your table. Not in the whole table, but from these last ones."
Can someone please help me?
Does this do what you want?
select country, roaming_partner, avg(pd_in_ok_rate) as avgrate
from table t
where period_duration >= date_sub(now(), interval -1 day)
group by country, roaming_partner;
This doesn't give you the detail on the average. You can use this as a subquery, if you want the detail as well
select t.*, cr.avgrate
from table t join
(select country, roaming_partner, avg(pd_in_ok_rate) as avgrate
from table t
where period_duration >= date_sub(now(), interval -1 day)
group by country, roaming_partner
) cr
on t.country = cr.country and t.roaming_partner = cr.roaming_partner
where period_duration >= date_sub(now(), interval -1 day);
I've got a table in MySQL:
| period_duration | duration | sample | corner | country | partner | ok_rate
+---------------------+----------+--------+----------+---------+-----------------------+-------------------------
| 2014-12-15 17:00:00 | 3600 | 1 | GRPS_INB | ARG | Charlie | 98 |
| 2014-12-15 17:00:00 | 3600 | 1 | GRPS_INB | DEU | Jack | 90 |
| 2014-12-15 17:00:00 | 3600 | 1 | GRPS_INB | NLD | Will | 100 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | ARG | Charlie | 98 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | DEU | Jack | 90 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | NLD | Will | 100 |
+-----------------+-------------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------------------+-------+
| period_duration | datetime | NO | PRI | 0000-00-00 00:00:00 | |
| duration | varchar(6) | YES | | NULL | |
| sample | varchar(2) | YES | | NULL | |
| corner | varchar(10) | YES | | NULL | |
| country | varchar(60) | NO | PRI | | |
| partner | varchar(60) | NO | PRI | | |
| ok_rate | int(8) | YES | | NULL | |
+-----------------+-------------+------+-----+---------------------+-------+
This table increases from hour to hour.
I need a shellscript that will check each line from the last hour and that has an "ok_rate" lower than a given value, and return them to me on a select.
The select should bring country, the partner, and the ok_rate.
Example:
Let's say I want it to be done with <=98%¨on "ok_rate".
My returning rows would be:
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | ARG | Charlie | 98 |
| 2014-12-15 20:00:00 | 3600 | 1 | GRPS_INB | DEU | Jack | 90 |
So far, I could only make it bring me the values below 98%, but not those that are also the last datetime that exists:
select country, partner, ok_rate from TABLE where ok_rate <= '98'
But how can I add a WHERE clause the makes it understand I want the last existing datetime that exists on period_duration too?
I mean something like:
SELECT country, partner, ok_rate FROM TABLE WHERE pdp_in_ok_rate <=98 AND (period_duration IS THE LAST ONE)?
This query should return what you want:
SELECT country, partner, ok_rate
FROM TABLE WHERE ok_rate <= 98
AND period_duration = (SELECT MAX(period_duration)
FROM TABLE)
Look in to GROUP BY for more detail because I'm not exactly sure what you want but something like this should help:
SELECT country, partner, ok_rate FROM TABLE
WHERE ok_rate <= '98'
GROUP BY `partner`, `country`
HAVING period_duration = MAX(period_duration);
I have a table visits like this:
+--------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| vis_id | int(11) | NO | | NULL | |
| unit | int(11) | NO | | NULL | |
| time_in | timestamp | NO | | CURRENT_TIMESTAMP | |
| time_out | timestamp | NO | | 0000-00-00 00:00:00 | |
| in_username | varchar(16) | NO | | NULL | |
| out_username | varchar(16) | NO | | NULL | |
+--------------+-------------+------+-----+---------------------+----------------+
and a table users like this:
+------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| fname | varchar(32) | NO | | NULL | |
| lname | varchar(32) | NO | | NULL | |
| date_added | timestamp | NO | | CURRENT_TIMESTAMP | |
| username | varchar(16) | NO | | NULL | |
| password | varchar(40) | NO | | NULL | |
| auth_level | int(1) | NO | | 1 | |
| last_login | timestamp | NO | | 0000-00-00 00:00:00 | |
+------------+-------------+------+-----+---------------------+----------------+
I want to be able to count how many times each user is in in_username AND out_username... The query I was using before looks like this:
select count(*) as "count", u.fname as "fname"
from visits v
inner join users as u on u.username = v.in_username
group by u.username order by u.fname
But that only returns how many in_username's there are... I'd like to have both in the same query if possible, so I could get results like this:
+----------+-----------+----------+
| count_in | count_out | fname |
+----------+-----------+----------+
| 118 | 224 | Bo |
| 27 | 64 | James |
| 147 | 138 | Jeremy |
| 23 | 37 | Jim |
| 182 | 172 | Robert |
| 120 | 158 | Tom |
+----------+-----------+----------+
Where count_in is how many times their username appears in visits.in_username, and count_out is how many times their username appears in visits.out_username
Everything I've tried with UNION seems to add the counts together, or removes rows for some reason. Any ideas?
Do a subquery to get each total, combine them with UNION, and then merge them with SUM().
SELECT SUM(count_in) count_in, SUM(count_out) count_out, fname
FROM (SELECT COUNT(*) count_in, 0 count_out, in_username fname
FROM visits v
GROUP BY fname
UNION
SELECT 0 count_in, COUNT(*) count_out, out_username fname
FROM visits v
GROUP BY fname) combined
I am performing a MySQL Query on two tables
keyword_stats
+-------------+---------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| keywordid | int(11) | NO | MUL | NULL | |
| campaignid | int(11) | NO | | NULL | |
| clicks | int(11) | NO | MUL | NULL | |
| impressions | int(11) | NO | MUL | NULL | |
| cost | decimal(10,2) | NO | MUL | NULL | |
| conversions | int(11) | NO | MUL | NULL | |
| timestamp | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
| statsdate | date | NO | MUL | NULL | |
+-------------+---------------+------+-----+-------------------+----------------+
AND
Keywords table
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| clientid | int(11) | NO | MUL | NULL | |
| campaignid | int(11) | NO | | NULL | |
| keywordid | int(11) | NO | MUL | NULL | |
| text | varchar(125) | NO | MUL | NULL | |
| status | varchar(10) | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
With the following SQL Query
SELECT
k.status, statsdate,
SUM( impressions ) AS impressions, SUM( clicks ) AS clicks,
SUM( conversions ) AS conversions, SUM( cost ) AS cost
FROM keyword_stats
LEFT JOIN
(
SELECT
text,keywordid,status
FROM keywords
) AS k USING (keywordid)
WHERE
campaignid = 56486451
AND statsdate BETWEEN '2011-03-01' AND '2011-03-23'
AND k.status = "enabled"
GROUP BY keywordid
ORDER BY conversions DESC, clicks DESC, impressions DESC LIMIT 0, 10
With the results of
+---------+------------+-------------+--------+-------------+-----------+
| status | statsdate | impressions | clicks | conversions | cost |
+---------+------------+-------------+--------+-------------+-----------+
| enabled | 2011-03-01 | 71256166 | 242079 | 4247 | 891572.71 |
| enabled | 2011-03-01 | 1101 | 10 | 1 | 43.19 |
| enabled | 2011-03-01 | 210 | 6 | 0 | 23.40 |
| enabled | 2011-03-01 | 331 | 4 | 0 | 15.29 |
| enabled | 2011-03-01 | 672 | 3 | 0 | 11.41 |
| enabled | 2011-03-01 | 486 | 2 | 0 | 8.93 |
| enabled | 2011-03-01 | 254 | 2 | 0 | 9.48 |
| enabled | 2011-03-01 | 2201 | 1 | 0 | 2.96 |
| enabled | 2011-03-01 | 581 | 1 | 0 | 3.25 |
| enabled | 2011-03-01 | 483 | 1 | 0 | 4.39 |
+---------+------------+-------------+--------+-------------+-----------+
10 rows in set (12.12 sec)
The query runs and performs as expected, except as you may see the first result contains unexpected results, since it is impossible for any keywords to have that amount of clicks, conversions or cost as a sum total I'm trying to figure where MySQL is combining the totals to achieve that result
EDIT ADDED KEYWORDID
+------------+---------+------------+-------------+--------+-------------+-----------+
| keywordid | status | statsdate | impressions | clicks | conversions | cost |
+------------+---------+------------+-------------+--------+-------------+-----------+
| 2147483647 | enabled | 2011-03-01 | 71256166 | 242079 | 4247 | 891572.71 |
| 101936939 | enabled | 2011-03-01 | 1101 | 10 | 1 | 43.19 |
| 23039553 | enabled | 2011-03-01 | 210 | 6 | 0 | 23.40 |
| 117364874 | enabled | 2011-03-01 | 331 | 4 | 0 | 15.29 |
| 18862051 | enabled | 2011-03-01 | 672 | 3 | 0 | 11.41 |
| 16695651 | enabled | 2011-03-01 | 486 | 2 | 0 | 8.93 |
| 14690232 | enabled | 2011-03-01 | 254 | 2 | 0 | 9.48 |
| 18046691 | enabled | 2011-03-01 | 2201 | 1 | 0 | 2.96 |
| 22232901 | enabled | 2011-03-01 | 581 | 1 | 0 | 3.25 |
| 15072731 | enabled | 2011-03-01 | 483 | 1 | 0 | 4.39 |
+------------+---------+------------+-------------+--------+-------------+-----------+
10 rows in set (11.99 sec)
keywordid is a PRIMARY KEY in neither table.
Most probably, you have a keywordid with lots of records in both tables which results in a cross join on this keywordid.
Also note that, first, a LEFT JOIN is redundant in your query since your are filtering on k.status, and, second, MySQL is not that good in optimizing inline views.
Just use this:
SELECT k.status, statsdate,
SUM( impressions ) AS impressions, SUM( clicks ) AS clicks,
SUM( conversions ) AS conversions, SUM( cost ) AS cost
FROM keyword_stats
JOIN keywords
USING (keywordid)
WHERE campaignid = 56486451
AND statsdate BETWEEN '2011-03-01' AND '2011-03-23'
AND k.status = "enabled"
GROUP BY
keywordid
ORDER BY
conversions DESC, clicks DESC, impressions DESC
LIMIT 0, 10
Do you need the information for each day? or do you need the data sum for all days?
If you want data for each day put "statsdate" in your group by expression.
Then, I thik that you don't need make a subquery. You can put the table name right in left join.
If you want the data for each "keywordid" put "keywordid" in the result fields. Status is not mandatory because always is "enabled"
Example:
SELECT
keywordid, statsdate,
SUM( impressions ) AS impressions, SUM( clicks ) AS clicks,
SUM( conversions ) AS conversions, SUM( cost ) AS cost
FROM keyword_stats
LEFT JOIN keywords k USING (keywordid)
WHERE
campaignid = 56486451
AND statsdate BETWEEN '2011-03-01' AND '2011-03-23'
AND k.status = "enabled"
GROUP BY keywordid, statsdate
ORDER BY conversions DESC, clicks DESC, impressions DESC LIMIT 0, 10