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.
Related
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).
have a table (fruits) like this:
+--------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| time | timestamp | NO | | CURRENT_TIMESTAMP | |
| fruit | varchar(16) | NO | | NULL | |
+--------------+-------------+------+-----+---------------------+----------------+
How can I select rows that have a "row neighbour" within the timerange of +/- 10 seconds?
This is my sample data:
INSERT INTO `fruits` VALUES (1,'2016-01-19 02:14:07','apple'),(2,'2016-01-19 02:14:13','banana'),(3,'2017-06-08 06:59:12','melon'),(4,'2017-06-08 06:57:12','strawberry');
This is my expected result set:
1 2016-01-19 02:14:07
2 2016-01-19 02:14:13
The rows with the id 3 and 4 have no neighbours within 10 seconds (+/-).
I thought I could do something like this:
SELECT TIME
FROM fruits
WHERE (DATE_SUB(TIME , INTERVAL 10 SECOND) > ANY
(SELECT TIME
FROM fruits))
AND (DATE_ADD(TIME , INTERVAL 10 SECOND) < ANY
(SELECT TIME
FROM fruits));
Which didn't work out well and is very complicated.
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.
I want to select the data that was inserted in the last 5 days, and if the rows are missing for that day then move on to the previous day, but it always have to return rows from the last 5 days.
The column which i'm trying to match is a DATETIME column
I've tried using this query
select * from `thum_{ROH}` where date >= NOW() - INTERVAL 5 DAY;
Now this return data from 2013-12-24 to 2013-12-22 because data on 2013-12-25 and 2013-12-26
is not available.
How can i modify the query to make it return the last 5 days data irrespective of missing rows. So in this case it will return data inserted on
2013-12-24
2013-12-23
2013-12-22
2013-12-19
2013-12-12
The days which are missing in between the dates above simply have no rows associated with them so they won't be returned.
I have also tried using
select distinct(date(date)), power from `thum_{ROH}` limit 5;
But this only selects some values in a specific date while skips on the rest. What i mean is that there are around 30 or more rows in each day which are present so the above query only returns around 2 or 3 rows per day.
I hope my question makes sense. I've been trying to find a solution without any success. Please provide any sort of advice on how can i achieve this. I would appreciate any help.
Thanks in advance,
Maxx
EDIT
Here is the table structure in question.
+-----------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+-------+
| thumType | int(11) | NO | PRI | 0 | |
| timestamp | int(10) unsigned | NO | PRI | 0 | |
| rune | char(15) | YES | | NULL | |
| date | datetime | YES | | NULL | |
| destruction | decimal(15,2) | YES | | NULL | |
| restoration | decimal(15,2) | YES | | NULL | |
| conjuration | decimal(15,2) | YES | | NULL | |
| alteration | decimal(15,2) | YES | | NULL | |
| illusion | int(10) unsigned | YES | | NULL | |
| power | decimal(15,2) | YES | | NULL | |
| magicka | decimal(15,2) | YES | | NULL | |
| health | decimal(15,2) | YES | | NULL | |
+-----------------+------------------+------+-----+---------+-------+
You can do this with a join:
select t.*
from `thum_{ROH}` t join
(select distinct date
from `thum_{ROH}`
order by date desc
limit 5
) as date5
on t.date = date5.date;
EIDT:
The above works if we assume that there is no time component.
We can fix that problem by doing:
select t.*
from `thum_{ROH}` t join
(select distinct date(date) as thedate
from `thum_{ROH}`
order by date desc
limit 5
) as date5
on date(t.date) = date5.thedate;
Assuming that the 'date' column is of type date, then we can solve this with a subquery to get the 5 most recent non-blank dates and then only select rows from those days.
SELECT *
FROM tablename
WHERE date IN (
SELECT distinct date FROM tablename ORDER BY date DESC LIMIT 5
)
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 !