I have a simple MySQL db listing the total time spent each user has spent online in seconds (just a string) per day. I would like to select the top 10% of those users for a given day and return there usernames.
Is there a way to do this in MySQL in a single query..? I've seen examples where you select the top 10 users, but not based on a percentage of total users...
Hope this will help you
I used CURRENT_DATE to limit search.
SELECT user_id, date, total_time FROM
(
SELECT user_id, #rownum:=#rownum+1 AS rownum
FROM TABLE_USER , (SELECT #rownum:=0) R
WHERE date = CURRENT_DATE
ORDER by total_time desc
) temp
where rownum < (select count(*) from TABLE_USER where date = CURRENT_DATE) / 10
try this
SELECT 0.1 * count(username) as percented_users FROM prices
GROUP BY username
You may try this way:
select * from table limit floor((select count(1) from table)*0.1)
Related
I have followed this tutorial on trying to get a win streak from my database of bets.
The data has a result (Win/Loss/Pending) and a date (Amongst other values)
Here is the SQL command I'm using...
SELECT *
FROM (SELECT Result,
MIN(date) as StartDate,
MAX(date) as EndDate,
COUNT(*) as Games
FROM (SELECT *,
(SELECT COUNT(*)
FROM bets G
WHERE G.result <> GR.result
AND G.date <= GR.date) as RunGroup
FROM bets GR WHERE user = 4 ORDER BY date DESC) A
GROUP BY result, RunGroup
ORDER BY Min(date)) A
WHERE result = 'Win'
ORDER BY Games DESC
The only difference with mine is I'm trying to filter a single users bets and not everyones bets but...I can see in my DB that there are 3 Win's in a row but my output is 2. Can anyone spot where I have gone wrong?
I want to get one row with the largest streak, which all I think I would need to do at this point is add LIMIT 1
Thanks
If you want all sequential wins summarized in one row, then I would suggest handling this has a gaps-and-islands problem. A simple method is to count the cumulative number of non-wins. This then assigns a group to each group of wins that can be used for aggregation:
select user, grp, count(*) as num_in_sequence,
min(date), max(date)
from (select b.*,
sum(result <> 'Win') over (partition by user order by date) as grp
from bets b
) b
where result = 'Win'
group by user, grp;
This is how I did it:
SELECT * FROM (SELECT result, MIN(date) as StartDate, MAX(date) as EndDate, COUNT(*) as Games FROM (SELECT date, result, (SELECT COUNT(*) FROM bets G WHERE G.result <> GR.result AND G.date <= GR.date AND user = ${uid}) as RunGroup FROM bets GR WHERE user = ${uid} ORDER BY date) A Where result = 'Win' GROUP BY result, RunGroup ORDER BY Min(date)) A ORDER BY Games DESC LIMIT 1
Basically I have a table like this:
Table Time:
ID.......Date
1......08/26/2016
1......08/26/2016
2......05/29/2016
3......06/22/2016
4......08/26/2015
5......05/23/2015
5......05/23/2015
6......08/26/2014
7......04/26/2014
8......08/26/2013
9......03/26/2013
The query should return like this
Year........CountNum
2016........4
2015........3
To find out which year does its value tend to increase in. I notice that I want to display the years that have more values (number of row in this case) than the previous year.
What I've done so far
SELECT Year, count(*) as CountNum
FROM Time
GROUP BY Year
ORDER BY CountNum DESC;
I don't know how to get the year from date format. I tried year(Date) function, but I got Null data.
Please help!
It should works fine.
select year(date), count(*) as countNum
from time
group by year(date)
order by countNum
Join the grouped data to itself with 1 year offset:
select
a.*
from
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) a
left join
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) b
on a._year = b._year-1
where a._n > b._n
order by 1
I have a lookup table that relates dates and people associated with those dates:
id, user_id,date
1,1,2014-11-01
2,2,2014-11-01
3,1,2014-11-02
4,3,2014-11-02
5,1,2014-11-03
I can group these by date(day):
SELECT DATE_FORMAT(
MIN(date),
'%Y/%m/%d 00:00:00 GMT-0'
) AS date,
COUNT(*) as count
FROM user_x_date
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 43200)
But, how can get the number of unique users, that have now shown up previously? For instance this would be a valid result:
unique, non-unique, date
2,0,2014-11-01
1,1,2014-11-02
0,1,2014-11-03
Is this possibly without having to rely on a scripting language to keep track of this data?
I think this query will do what you want, at least it seems to work for your limited sample data.
The idea is to use a correlated sub-query to check if the user_id has occurred on a date before the date of the current row and then do some basic arithmetic to determine number of unique/non-unique users for each date.
Please give it a try.
select
sum(u) - sum(n) as "unique",
sum(n) as "non-unique",
date
from (
select
date,
count(user_id) u,
case when exists (
select 1
from Table1 i
where i.user_id = o.user_id
and i.date < o.date
) then 1 else 0
end n
from Table1 o
group by date, user_id
) q
group by date
order by date;
Sample SQL Fiddle
I didn't include the id column in the sample fiddle as it's not needed (or used) to produce the result and won't change anything.
This is the relevant question: "But, how can get the number of unique users, that have now shown up previously?"
Calculate the first time a person shows up, and then use that for the aggregation:
SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date;
I would then use this as a subquery for another aggregation:
SELECT v.date, v.NumVisits, COALESCE(fv.FirstVisit, 0) as NumFirstVisit
FROM (SELECT date, count(*) as NumVisits
FROM user_x_date
GROUP BY date
) v LEFT JOIN
(SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date
) fv
ON v.date = fv.date;
I have a table of production readings and need to get a result set containing a row for the min(timestamp) for EACH hour.
The column layout is quite simple:
ID,TIMESTAMP,SOURCE_ID,SOURCE_VALUE
The data sample would look like:
123,'2013-03-01 06:05:24',PMPROD,12345678.99
124,'2013-03-01 06:15:17',PMPROD,88888888.99
125,'2013-03-01 06:25:24',PMPROD,33333333.33
126,'2013-03-01 06:38:14',PMPROD,44444444.44
127,'2013-03-01 07:12:04',PMPROD,55555555.55
128,'2013-03-01 10:38:14',PMPROD,44444444.44
129,'2013-03-01 10:56:14',PMPROD,22222222.22
130,'2013-03-01 15:28:02',PMPROD,66666666.66
Records are added to this table throughout the day and the source_value is already calculated, so no sum is needed.
I can't figure out how to get a row for the min(timestamp) for each hour of the current_date.
select *
from source_readings
use index(ID_And_Time)
where source_id = 'PMPROD'
and date(timestamp)=CURRENT_DATE
and timestamp =
( select min(timestamp)
from source_readings use index(ID_And_Time)
where source_id = 'PMPROD'
)
The above code, of course, gives me one record. I need one record for the min(hour(timestamp)) of the current_date.
My result set should contain the rows for IDs: 123,127,128,130. I've played with it for hours. Who can be my hero? :)
Try below:
SELECT * FROM source_readings
JOIN
(
SELECT ID, DATE_FORMAT(timestamp, '%Y-%m-%d %H') as current_hour,MIN(timestamp)
FROM source_readings
WHERE source_id = 'PMPROD'
GROUP BY current_hour
) As reading_min
ON source_readings.ID = reading_min.ID
SELECT a.*
FROM Table1 a
INNER JOIN
(
SELECT DATE(TIMESTAMP) date,
HOUR(TIMESTAMP) hour,
MIN(TIMESTAMP) min_date
FROM Table1
GROUP BY DATE(TIMESTAMP), HOUR(TIMESTAMP)
) b ON DATE(a.TIMESTAMP) = b.date AND
HOUR(a.TIMESTAMP) = b.hour AND
a.timestamp = b.min_date
SQLFiddle Demo
With window function:
WITH ranked (
SELECT *, ROW_NUMBER() OVER(PARTITION BY HOUR(timestamp) ORDER BY timestamp) rn
FROM source_readings -- original table
WHERE date(timestamp)=CURRENT_DATE AND source_id = 'PMPROD' -- your custom filter
)
SELECT * -- this will contain `rn` column. you can select only necessary columns
FROM ranked
WHERE rn=1
I haven't tested it, but the basic idea is:
1) ROW_NUMBER() OVER(PARTITION BY HOUR(timestamp) ORDER BY timestamp)
This will give each row a number, starting from 1 for each hour, increasing by timestamp. The result might look like:
|rest of columns |rn
123,'2013-03-01 06:05:24',PMPROD,12345678.99,1
124,'2013-03-01 06:15:17',PMPROD,88888888.99,2
125,'2013-03-01 06:25:24',PMPROD,33333333.33,3
126,'2013-03-01 06:38:14',PMPROD,44444444.44,4
127,'2013-03-01 07:12:04',PMPROD,55555555.55,1
128,'2013-03-01 10:38:14',PMPROD,44444444.44,1
129,'2013-03-01 10:56:14',PMPROD,22222222.22,2
130,'2013-03-01 15:28:02',PMPROD,66666666.66,1
2) Then on the main query we select only rows with rn=1, in other words, rows that has lowest timestamp in each hourly partition (1st row after sorted by timestamp in each hour).
Lets say I have a table of messages that users have sent, each with a timestamp.
I want to make a query that will tell me (historically) the most number of messages a user ever sent in an hour.
So in other words, in any given 1 hour period, what was the most number of messages sent.
Any ideas?
Assuming timestamp to be a DATETIME - otherwise, use FROM_UNIXTIME to convert to a DATETIME...
For a [rolling] count within the last hour:
SELECT COUNT(*) AS cnt
FROM MESSAGES m
WHERE m.timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 1 HOUR)
AND NOW()
GROUP BY m.user
ORDER BY cnt DESC
LIMIT 1
If you want a specific hour, specify the hour:
SELECT COUNT(*) AS cnt
FROM MESSAGES m
WHERE m.timestamp BETWEEN '2011-06-06 14:00:00'
AND '2011-06-06 15:00:00'
GROUP BY m.user
ORDER BY cnt DESC
LIMIT 1
Need more details on table structure etc. but something like:
select date(timestmp), hour(timestmp) , count(*)
from yourtable group by date(timestmp) , hour(timestmp)
order by count(*) DESC
limit 100;
would give you hte desired result.
Something like this should work:
SELECT MAX(PerHr) FROM
(SELECT COUNT(*) AS PerHr FROM messages WHERE msg_uid=?
GROUP BY msg_time/3600) t
I suspect this would be horribly slow, but for an arbitrary historical max hour, something like this might work (downvote me if I'm way off, I'm not a MySQL person):
SELECT base.user, base.time, COUNT(later.time)
FROM messages base
INNER JOIN messages later ON later.time BETWEEN base.time AND DATE_ADD(base.time, INTERVAL 1 HOUR) AND base.user = later.user
WHERE base.user = --{This query will only work for one user}
GROUP BY base.user, base.time
ORDER BY COUNT(later.time) DESC
LIMIT 1