I have a table with a date stamp E.g (1241037505). There's also a column with the number of views.
The data stamp resembles when it was created.
So I want to select the top viewed threads from the past week.
How do I do this?
Try this:
SELECT * WHERE
DATEDIFF(NOW(),created_date) < 7
SELECT * FROM table WHERE createdon > SUBDATE(NOW(), '7 day') ORDER BY hits DESC;
See: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_subdate
The data you're currently tracking isn't going to allow you to select the top viewed in the last week. It will show you the top viewed over all time, or the most viewed items created in the last week. If something was created two weeks ago, but was viewed more than anything else during the last week you cannot determine that from the data you're tracking. One way I can see to do it would be to track the number of hits each content item gets each day of the week.
create table daily_hits {
cid integer, -- content id points to the table you already have
dotw smallint, -- 0-6 or similar
hits integer
PRIMARY KEY (cid, dotw)
}
Whenever you increase the hit count on the content item, you would also update the daily_hits table for the given content id and day of the week. You would need a function that converted the current date/time to a day of the week. MySql provides DAYOFWEEK for this purpose.
To get the most viewed in the last week, you could query like this:
SELECT cid, SUM(hits) FROM daily_hits GROUP BY cid ORDER BY SUM(hits) DESC
You will need some type of scheduled job that deletes the current day of the week at midnight so you aren't accumulating forever and essentially performing the same accumulation happening on the hits column of the current table.
SELECT * FROM table WHERE Date_Created > (7 days ago value) ORDER BY Hits LIMIT 0,100
or you could use this (per WishCow's Answer)
SELECT * FROM table WHERE Date_Created > SUBDATE(NOW(), '7 day') ORDER BY Hits LIMIT 0,100
Related
This is a followup to this question MySql Select rows with 30 minutes difference in date, albeit similar in concept the solution needed might be different.
I have a MySql-8.0/MariaDb-10.4 table that contains a list of site visits of different visitors:
I want to create a query that returns the last visit of each visit session, where the session definition is where the CreatedAt date is 30 min or more from the previous visits.
So in my case, I should be returning row 7 (Id column), row 12 and row 13. Note also that a session can be more than 30 minutes, as long as each visit succeeds a previous visit with less than 30min.
The neat solution suggest by #EugenRieck was as follows:
SELECT
late.*
FROM activities AS late
LEFT JOIN activities AS early
ON late.VisitorId=early.VisitorId
AND late.CreatedAt>early.CreatedAt
AND late.CreatedAt<=DATE_ADD(early.CreatedAt, INTERVAL +30 MINUTE)
WHERE early.Id IS NULL
-- Maybe: AND late.VisitorId='26924c19-3cd1-411e-a771-5ebd6806fb27'
-- Maybe: ORDER BY late.CreatedAt
It works great, but it works by returning the first visit in each visit session, not the last visit. I tried to modify to work as i wanted but with no luck. Please help.
This is a variant of gap-and-islands problem. But you can handle it using lead(). Just check if the next createdAt is over 30 minutes from the value in a given row. That is the last row for a session:
select a.*
from (select a.*,
lead(createdAt) over (partition by visitorid order by createdat) as next_ca
from activities a
) a
where next_ca > createdAt + interval 30 minute;
Usually, in this situation you would want the last row as well. You would get that with or next_ca is null.
I have database table in MySQL, which consist of the following fields:
id
user_id
timestamp
The table is a simple log of visitors. I am trying to get the following numbers in one query:
Distinct user_id's for a specific time period (30 days)
Amount of these user_id's, which already exist in the table, regardless of time period
I have been able to do it within the period with this simple query:
SELECT
COUNT(DISTINCT user_id) AS 'count_distinct',
COUNT(user_id) AS 'count_all'
FROM
table
WHERE
timestamp BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE();
Running this query gives me the count of distinct user_id's and the count of all user_id's within the time period. I can then apply the math myself to get the count of new vs. returning visitors - for that period. What I am trying to figure out is how many distinct user_id's, who visited within 30 days, who has also visited at any previous point in time.
I hope you can help me solve this.
I had a sql query I would run that would get a rolling sum (or moving window) data set. I would run this query for every 7 days, increase the interval number by 7 (28 in example below) until I reached the start of the data. It would give me the data split by week so I can loop through it on the view to create a weekly graph.
SELECT *
FROM `table`
WHERE `row_date` >= DATE_SUB(NOW(), INTERVAL 28 DAY)
AND `row_date` <= DATE_SUB(NOW(), INTERVAL 28 DAY)
This is of course very slow once you have several weeks worth of data. I wanted to replace it with a single query. I came up with this.
SELECT *
CONCAT(YEAR(row_date), '/', WEEK(row_date)) as week_date
FROM `table`
GROUP BY week_date
ORDER BY row_date DESC
It appeared mostly accurate, except I noticed the current week and the last week of 2015 was much lower than usual. That's because this query gets a week starting on Sunday (or Monday?) meaning that it resets weekly.
Here's a data set of employees that you can use to demonstrate the behavior.
CREATE TABLE employees (
id INT NOT NULL,
first_name VARCHAR(14) NOT NULL,
last_name VARCHAR(16) NOT NULL,
row_date DATE NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO `employees` VALUES
(1,'Bezalel','Simmel','2016-12-25'),
(2,'Bezalel','Simmel','2016-12-31'),
(3,'Bezalel','Simmel','2017-01-01'),
(4,'Bezalel','Simmel','2017-01-05')
This data will return the last 3 rows on the same data point on the old query (last 7 days) assuming you run it today 2017-01-06, but only the last 2 rows on the same data point on the new query (Sunday to Saturday).
For more information on what I mean by rolling or moving window, see this English stack exchange link.
https://english.stackexchange.com/questions/362791/word-for-graph-that-counts-backwards-vs-graph-that-counts-forwards
How can I write a query in MySQL that will bring me rolling data, where the last data point is the last 7 days of data, the previous point is the previous 7 days, and so on?
I've had to interpret your question a lot so this answer might be unsuitable. It sounds like you are trying to get a graph showing data historically grouped into 7-day periods. Your current attempt does this by grouping on calendar week instead of by 7-day period leading to inconsistent size of periods.
So using a modification of your dataset on sql fiddle ( http://sqlfiddle.com/#!9/90f1f2 ) I have come up with this
SELECT
-- Figure out how many periods of 7 days ago this record applies to
FLOOR( DATEDIFF( CURRENT_DATE , row_date ) / 7 ) AS weeks_ago,
-- Count the number of ids in this group
COUNT( DISTINCT id ) AS number_in_week,
-- Because this is grouped, make sure to have some consistency on what we select instead of leaving it to chance
MIN( row_date ) AS min_date_in_week_in_dataset
FROM `sample_data`
-- Groups by weeks ago because that's what you are interested in
GROUP BY weeks_ago
ORDER BY
min_date_in_week_in_dataset DESC;
I have a table called 'events'.
It contains eventID (INT), eventDateTime(DATETIME), and eventMessage(VARCHAR).
I want to be able group the rows by eventDateTime where there is another row with eventDateTime within 1 hour each side. This should propogate forever (for example a group should be able go on for years, as long as there is never a gap longer than an hour between a linking chain of eventDateTime values within that time period. Ideally I want to end up selecting MIN(eventID) for each group, and both the MIN and MAX of eventDateTime which will give me the time span in which the group runs.
I assume I need some kind of iterating loop to do this? Where would I start?
Let's start from subqueries we need
SET #row_number1 = 0;
SET #row_number2 = 0;
The query returns us the events table ordered with row numbers (rn)
SELECT
(#row_number1:=#row_number1 + 1) AS rn, eventID, eventDateTime
FROM
events
ORDER BY eventDateTime
Let's mar them as SUB1 and SUB2
Then let's join them
select *
from SUB1 join SUB2 on sub1.rn=sub2.rn+1
So we have in one row 2 eventDateTime of current and next row and can calculate time difference
TIMESTAMPDIFF(HOUR, SUB1.eventDateTime, SUB2.eventDateTime) as hoursDiff
Then we can add HAVING hourDiff>1 to have rule breaking intervals. For such records SUB1.eventDateTime is the end of previous group but SUB2.eventDateTime is the beginning of next group.
So our query will return us
SUB1.eventID as previousGroupEndEventId,
SUB1.eventDateTime as previousGroupEndeventDateTime,
SUB2.eventID as currentGroupStartEventId,
SUB2.eventDateTime as currentGroupStarteventDateTime,
TIMESTAMPDIFF(HOUR, SUB1.eventDateTime, SUB2.eventDateTime) as breakInterval
And you can use the query results to get all your info
For complex problems requiring some form of looping, some databases allow recursive queries, but apparently not mysql.
Fortunately, in your case I don't think it is necessary. You can instead look for any rows which don't have another row in the preceeding hour thus:
select *
from events as A
where not exists (
select 1
from events as B
where B.eventDateTime < A.eventDateTime
and B.eventDateTime > DATE_ADD(A.eventDateTime, INTERVAL -1 HOUR)
)
Example kept simple. Fix up the details to meet your requirements.
Working example is here: http://sqlfiddle.com/#!9/c3b73c/1
Say I have a table with two columns
TimeStamp of type TIMESTAMP
A of type FLOAT
This table is created and updated by an external application, so inserts and updates are outside of my control. The table design can't be altered in any way.
What I need to do is select each entry closest to and before 10AM for each day during the entire past month.
Thanks in advance.
The inner pre-query should get on a per year/month basis, prior to the month you are currently in. This is forced by a SQLVariable created by the formatted 'YYYY-MM-01' date, such as today... 2012-03-19, keep just year/month but force 01. This also implies timestamp of 12:00:00 am (midnight). The NEXT # variable is to determine the first of the month PRIOR to the one just computed... thus 2012-02-01. That builds the variables for the WHERE clause queried against your table of timestamp/float values.
Now, you can get the maximum time, grouped by just the common date portion of the timestamp, but retaining the full actual date AND time of the entry where the HOUR() of the entry is before 10am...
From that, re-join back to the original table where the FINAL "LastPerDay" time matches the per-day basis. Now, you MAY get multiple entries if the actual last timestamp entry for the same day actually HAS multiple exact time entries to the granularity of hh:mm:ss (or whatever precision)
select
PreQuery.JustTheDate,
YT2.FloatColumnName
from
( select
Date_Format( YT.TimeStampColumn, '%Y-%m-%d' ) JustTheDate,
max( YT.TimeStampColumn ) as LastPerDay
from
( select #FirstOfThisMonth := Date_Format( '%Y-%m-01' ),
#FirstOfPriorMonth := Date_Sub( #FirstOfThisMonth, interval 1 month ) ) sqlvars,
YourTable YT
where
YT.TimeStampColumn >= #FirstOfPriorMonth
AND YT.TimeStampColumn < #FirstOfThisMonth
AND Hour( YT.TimeStampColumn ) < 10
group by
`JustTheDate`
order by
`JustTheDate` DESC ) PreQuery
JOIN YourTable YT2
ON PreQuery.LastPerDay = YT2.TimeStampColumn