WeatherStation : Mysql query join & average on tables - mysql

I have two tables like that :
temperature :
+---------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| date | datetime | YES | UNI | NULL | |
| capteur | int(11) | YES | | NULL | |
| valeur | float(3,1) | YES | | NULL | |
+---------+---------------------+------+-----+---------+----------------+
humidite :
+---------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| date | datetime | YES | UNI | NULL | |
| capteur | int(11) | YES | | NULL | |
| valeur | int(11) | YES | | NULL | |
+---------+---------------------+------+-----+---------+----------------+
I have values recorded on those two tables, not at the same time (Around 1 record each minute).
If I enter this command, I get average values for each hour for the last 24h (so, 24 rows) :
$sql->query('SELECT hour(date) AS humhour,ROUND(AVG(valeur),1) AS avghum FROM humidite WHERE date >= (now() - INTERVAL 1 DAY) GROUP BY HOUR(date) ORDER BY DATE;');
Now, I try to get the same thing, but with both tables. Ie, for all value between 0h00 and 0h59, I want average of all temperature and average of all humidity values.
I try this command :
$result = $sql->query('
SELECT hour(temperature.date) AS hourtemp,
hour(humidite.date) AS hourhum,
ROUND(AVG(temperature.valeur),1) AS avgtemp,
ROUND(AVG(humidite.valeur),1) AS avghum
FROM temperature
INNER JOIN humidite on hour(temperature.date) = hour(humidite.date)
WHERE temperature.date >= (now() - INTERVAL 1 DAY)
GROUP BY HOUR(date)
ORDER BY DATE;');
An idea ?
Thank you !

Related

How can I select rows newer than a week?

Using MariaDB 10, I'd like to query article table for the past week articles:
Here is my query:
SELECT * FROM article WHERE category="News" AND created_at < NOW() - INTERVAL 1 WEEK ORDER BY created_at DESC;
But it returns all articles instead.
explain article ;
+-------------+-----------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+-------------------+----------------+
| id | int(6) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(150) | NO | | NULL | |
| content | mediumtext | NO | | NULL | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | |
| category | varchar(64) | NO | | test | |
How can I achieve this?
The logic is backwards. You want > not <:
SELECT a.*
FROM article a
WHERE category = 'News' AND
created_at > NOW() - INTERVAL 1 WEEK
ORDER BY created_at DESC;
For performance, you would want an index on article(category, created_at).

Cant figure out self join query

I have a table with the following structure.
+-----------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+-------+
| linq_order_num | char(32) | NO | PRI | NULL | |
| order_status_id | int(11) | YES | MUL | NULL | |
| order_id | varchar(100) | YES | | NULL | |
| item_name | varchar(120) | YES | | NULL | |
| item_cost | float | YES | | NULL | |
| custmer_id | int(11) | YES | MUL | NULL | |
| order_date_time | datetime | YES | | NULL | |
| order_category | varchar(120) | YES | | NULL | |
| ordered_by | int(11) | YES | MUL | NULL | |
| linq_shipping_cost | float | YES | | NULL | |
| website_shipping_cost | float | YES | | NULL | |
| total_cost | float | YES | | NULL | |
| advance_amount | float | YES | | NULL | |
| website | varchar(120) | YES | | NULL | |
| other | varchar(120) | YES | | NULL | |
| rvn | int(11) | YES | | NULL | |
| received_date | datetime | YES | | NULL | |
| delivered_date | datetime | YES | | NULL | |
| store_id | int(11) | YES | MUL | NULL | |
+-----------------------+--------------+------+-----+---------+-------+
So for every day I need to find the total order cost.I can get it by using this query.
select sum(total_cost), date_format(order_date_time,"%Y-%m-%d") from
order_item group by date_format(order_date_time,"%Y-%m-%d")
Also I need the total remaining amount paid on the delivered dates.
select sum(total_cost-advance_amount),date_format(delivered_date,"%Y-%m-%d")
from order_item group by date_format(delivered_date,"%Y-%m-%d")
Not all the days, orders will happen and not all the days deliveries will happen.If there is day with no orders the total cost for that day should be shown as zero and the total remaining amount shown should be sum of (total_cost-advance_amount) for the day.
Is there a way I could combine the above two queries in one query and get the result?
So to summarise for a particular day d:
I need sum(total_cost) where ordered_date_time = d ,
I need sum(total_cost -advance_amount) where delivered_date = d
Essentially looking for a table like this:
Date Total Cost Total Delivery Amounts
d 500 2000
d1 0 900
d2 900 0
I tried using a subquery. The problem is it doesn't display the cases for d1, where is total cost for that day is 0.
Query:
select
date_format(order_date_time,"%Y-%m-%d") date,
sum(total_cost) total,
sum(advance_amount) advance_amount,
IFNULL( (select sum(total_cost-advance_amount)
from order_item a
where date_format(a.delivered_date,"%Y-%m-%d") = date_format(d.order_date_time,"%Y-%m-%d") ),0 ) delivery_amount
from order_item d
group by date_format(order_date_time,"%Y-%m-%d"), delivery_amount
You can use your two queries as derived tables and join them on date. The problem is, that you would need a FULL OUTER JOIN, which is not supported by MySQL. So you first need to extract all the dates from both columns
select date(order_date_time) as d from order_item
union
select date(delivered_date) as d from order_item
und use a left join with your queries
select
dates.dt,
coalesce(tc.total_cost, 0),
coalesce(tm.total_remaining, 0)
from (
select date(order_date_time) as dt from order_item
union
select date(delivered_date) as dt from order_item
) dates
left join (
select sum(total_cost) as total_cost, date(order_date_time) as dt
from order_item
group by dt
) tc using(dt)
left join (
select sum(total_cost-advance_amount) as total_remaining, date(delivered_date)
from order_item
group by dt
) tm using(dt)
I also replaced date_format(..) with date(..). You can format the dates in the outer select or in your application.

SELECT Rows Older Than Date Only If Row Does Not Have Row Newer Than Date

I have the below table where I would like to 'prune' out nicks who have not gained points in 1 week. I'm new to MySQL and I'm not sure how to best SELECT these rows. Your help is greatly appreciated!
Here is what I have so far that is not yielding correct results. The results this yields are nicks who have earned points at any time it seems.
SELECT * FROM points_log p1
INNER JOIN points_log p2 ON p1.nick = p2.nick
AND p1.dt < NOW() - INTERVAL 1 WEEK
WHERE p2.dt > NOW() - INTERVAL 1 WEEK LIMIT 10;
Here is the table:
mysql> describe points_log;
+-------------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+-----------------------+------+-----+---------+----------------+
| id | mediumint(8) unsigned | NO | PRI | NULL | auto_increment |
| nick | char(25) | NO | PRI | NULL | |
| amount | decimal(10,4) | YES | MUL | NULL | |
| stream_online | tinyint(1) | NO | MUL | NULL | |
| modification_type | tinyint(3) unsigned | NO | MUL | NULL | |
| dt | datetime | NO | PRI | NULL | |
+-------------------+-----------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
You can get the nicks who have scored in the past week using an aggregation:
SELECT pl.nick
FROM points_log pl
GROUP BY pl.nick
HAVING MAX(pl.dt) < NOW() - INTERVAL 1 WEEK;
I'm not sure what you want as final output, but this will return the nicks that have scored in the past week.

Order by number of views in last hour [MySQL]

I have a table which holds all views for the last 24 hours. I want to pull all pages ordered by a rank. The rank should be calculated something like this:
rank = (0.3 * viewsInCurrentHour) * (0.7 * viewsInPreviousHour)
I want the prefferably in one single query. Is this possible, or do I need to make 2 queries (one for the current hour and one for the last hour and then just aggregate them)?
Here is the DESCRIBE of the table accesslog:
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| aid | int(11) | NO | PRI | NULL | auto_increment |
| sid | varchar(128) | NO | | | |
| title | varchar(255) | YES | | NULL | |
| path | varchar(255) | YES | | NULL | |
| url | text | YES | | NULL | |
| hostname | varchar(128) | YES | | NULL | |
| uid | int(10) unsigned | YES | MUL | 0 | |
| timer | int(10) unsigned | NO | | 0 | |
| timestamp | int(10) unsigned | NO | MUL | 0 | |
+-----------+------------------+------+-----+---------+----------------+
select
url,
sum(timestamp between subdate(now(), interval 2 hour) and subdate(now(), interval 1 hour)) * .3 +
sum(timestamp between subdate(now(), interval 1 hour) and now()) * .7 as rank
from whatever_your_table_name_is_which_you_have_kept_secret
where timestamp > subdate(now(), interval 2 hour)
group by url
order by rank desc;
The sum(condition) works because in mysql trye is 1 and false is 0, so summing a condition is the same as what some noobs write as sum(case when condition then 1 else 0 end)
Edit:
Note the addition of where timestamp > subdate(now(), interval 2 hour) to improve performance, because only these records contribute to the result.

mysql query: data from last three months

I am doing a query that is retrieving some data from the past three months, the only problem is that some of the data I am getting doesn't have entries in certain months. Since they have no entries I'd like to mark that month as 0.
My first thought was the create a temp table and left join the labels that I need out of it. But that hasnt been successful.
Can anyone think of a way to do this?
Example: I want the last 3 months of Data and I am getting
'Component', 1325.1988
'Component', 554.1652
'Component', 103.6668
'Development', 203.4163
'Development', 59.4500
'Development', 19.7498
'Flash Assets', 285.5334
'Flash Assets', 302.1501
'Flash Assets', 61.1836
'Release', 0.6000
'Release', 2.3666
'Repackage', 416.2169
'Repackage', 5195.0839
'Repackage', 4.5667
'Source Diff', 1.9000
Where 'Source Diff' and 'Release' don't have 3 entries.
Thanks
Query
SELECT bt.name as 'Labels',
SUM(TIME_TO_SEC(TIMEDIFF(bs.eventtime, b.submittime))/60) AS 'Data'
FROM builds b JOIN buildstatuses bs ON bs.buildid = b.id JOIN buildtypes bt
ON bt.id = b.buildtype WHERE DATE(b.submittime)
BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 MONTH) AND DATE(CURDATE())
AND bs.status LIKE 'Started HANDLER' AND b.buildtype != 11
AND b.buildtype != 5 AND b.buildtype != 4 GROUP BY bt.name, MONTH(b.submittime);
Table Schema
builds
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| submittime | datetime | NO | | NULL | |
| buildstatus | int(11) | NO | | NULL | |
| buildtype | varchar(20) | NO | | NULL | |
| buildid | int(11) | NO | | NULL | |
+---------------+------------------+------+-----+---------+----------------+
buildtypes
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(200 | NO | | NULL | |
+---------------+------------------+------+-----+---------+----------------+
buildstatuses
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| buildid | int(11) | NO | MUL | NULL | |
| eventtime | datetime | NO | | NULL | |
+------------+----------+------+-----+---------+----------------+
Here are some similar questions:
How to get values for every day in a month
Group by day and still show days without rows?
MySQL: filling empty fields with zeroes when using GROUP BY