Get highest value for each date - mysql

I have a table that logs every time a user completes a survey. It looks a bit like this:
surveyID author timestamp
-----------------------------------------------
1 person1 1461840669000
2 person2 1461840670000
3 person1 1461840680000
I'm trying to run a query that shows me the top surveyor every day (i.e. the person that does the highest number of surveys per day) since April 1st.
So far I've tried this:
SELECT author,
COUNT (DISTINCT surveyid) AS num_surveys,
STRFTIME_UTC_USEC(creation_time*1000, "%Y-%m-%d") AS date,
FROM myTable
WHERE creation_time > 1459468800000 //since April 1st
GROUP BY date, author
ORDER BY 3 DESC,2 DESC;
Which gives me this result:
author num_surveys date
------------------------------------
user1 116 2016-04-27
user2 109 2016-04-27
user3 99 2016-04-27
user3 102 2016-04-28
user1 98 2016-04-28
user2 97 2016-04-28
However, I would really just like the top record from each day:
author num_surveys date
------------------------------------
user1 116 2016-04-27
user3 102 2016-04-28 etc...
I've tried MAX() and TOP() in various places but none of them have worked so far hence the above example of my query that gets me closest to what I want... Any suggestions would be much appreciated. I'm very new to SQL!
EDIT
Thanks for the suggestions to far. Have managed to get it to work with:
DEFINE INLINE TABLE A
SELECT author,
COUNT (DISTINCT featureid) AS num_surveys,
STRFTIME_UTC_USEC(creation_time*1000, "%Y-%m-%d") AS date,
FROM placesense.surveys
WHERE creation_time > 1459468800000
GROUP BY date, author
ORDER BY 3 DESC,2 DESC;
SELECT
MAX(num_surveys),
date
FROM A AS B
WHERE date = B.date
GROUP BY date
Any other more efficient suggestions welcome though.

A pretty simple way uses a correlated subquery:
select t.*
from t
where t.num_surveys = (select max(t2.num_surveys) from t t2 where t2.date = t.date);
Note: this will return duplicates for a date in the case of ties.

SELECT MAX( surveyid) AS m_surveys,
STRFTIME_UTC_USEC(creation_time*1000, "%Y-%m-%d") AS date,
FROM myTable
WHERE creation_time > 1459468800000 //since April 1st
GROUP BY date, author
ORDER BY 3 DESC,2 DESC;

Related

How to display the days when there are no records in MariaDB?

I have the following table called employees:
employee
name
101
John
102
Alexandra
103
Ruth
And the table called records:
employee
assistance
101
2022-02-01
101
2022-02-02
101
2022-02-07
Let's suppose that I want to display the employee number, name and the days of the month in which there were absences between 2022-02-01 and 2022-02-07 (taking into account that days 05 and 06 are weekends). In that case, the result would be the following:
employee
name
absence
101
John
4,5
How do I get that result?
So far I have developed a query where the days of the month in which there are attendances are displayed. Said query is as follows:
SELECT e.employee,
e.name,
r.assistance AS assistance,
OF employees and
JOIN LEFT(SELECT employee, GROUP_CONCAT(DIFFERENT EXTRACT(DAY SINCE assistance)
ORDER BY STATEMENT(DAY FROM assistance)) AS assistance FROM records
WHERE assistance BETWEEN '2022-02-01' AND '2022-02-07' GROUP BY employee) r ON e.employee = employee
WHERE (r.no_employee IS NOT NULL) ORDER BY name ASC
I would like to know how to implement the days in which there were absences and not consider the weekends. I've done several tests but I'm still stuck. I'm working with MariaDB 10.4.11
You use a recursive common table expression (requires mariadb 10.2+ or mysql 8) to get the list of dates in the date range, and join against that:
with recursive date_range as (
select '2021-12-01' dt
union all
select dt + interval 1 day from date_range where dt < '2021-12-07'
)
select employee.employee, group_concat(day(date_range.dt) order by date_range.dt) faults
from date_range
cross join employee
left join records on records.employee=employee.employee and records.assistance=date_range.dt
where weekday(date_range.dt) < 5 and records.employee is null
group by employee.employee
fiddle
If you are just looking for one employee, add that as a where condition.

How to select rows in every day between two dates using MySQL

I want to keep track of users logged in every day between two dates.
Let's say I have a table my_table like this:
user_id
login_datetime
1
2021-10-02 10:00:00
1
2021-10-02 12:00:00
2
2021-10-02 12:20:00
1
2021-10-03 17:00:00
1
2021-10-04 22:00:00
2
2021-10-04 23:00:00
and given date range is from '2021-10-02' to '2021-10-04'.
I want to get user_id = 1 in this case, because user_id = 2 is not logged in at '2021-10-03'
result
user_id
login_date
1
2021-10-02
1
2021-10-03
1
2021-10-04
Is there any solution for this?
One approach uses aggregation:
SELECT user_id
FROM my_table
WHERE login_datetime >= '2021-10-02' AND login_datetime < '2021-10-05'
GROUP BY user_id
HAVING COUNT(DISTINCT DATE(login_datetime)) = 3; -- range has 3 dates in it
Demo
The HAVING clause asserts that any matching user must have 3 distinct dates present, which would imply that such a user would have login activity on all dates from 2021-10-02 to 2021-10-04 inclusive.
Edit:
To get the exact output in your question, you may use:
SELECT DISTINCT user_id, DATE(login_datetime) AS login_date
FROM my_table
WHERE user_id IN (
SELECT user_id
FROM my_table
WHERE login_datetime >= '2021-10-02' AND login_datetime < '2021-10-05'
GROUP BY user_id
HAVING COUNT(DISTINCT DATE(login_datetime)) = 3
);

Select nearest date in the interval

I'm trying to select rows in which 3+ posts is in the interval 14 days.
For example:
User | id_post | date
1 | 12 | 2018-01-01
1 | 13 | 2018-01-05
1 | 14 | 2018-01-21
1 | 15 | 2018-01-27
1 | 16 | 2018-01-29
2 | 17 | 2018-01-01
2 | 18 | 2018-01-20
2 | 19 | 2018-02-17
2 | 20 | 2018-03-07
2 | 21 | 2018-04-29
User = OwnerUserId
date = CreationDate
In this case I need to return just User 1 because he has posts which are in 14 days.
Please, help me how I can get it. Thank you
Update: A user should have posts which were published in the interval of 14 days. It can be more, for example if the last day is in 2019 but in 2018 there was 3posts published within 14 days - it's ok
now i have (data get from data.stackexchange stackoverflow) and tried to apply
select OwnerUserId from Posts as p
where OwnerUserId in (select Users.id from Users WHERE YEAR (Users.CreationDate) >= 2017)
AND YEAR (p.CreationDate) >= 2018
AND p.Tags like '%sql%'
join (select OwnerUserId, CreationDate as startdate, dateadd(day,14,CreationDate) as enddate
from Posts) as r
on p.OwnerUserId = r.OwnerUserId and p.CreationDate between r.startdate and r.enddate
group by p.OwnerUserId, CreationDate
having count(*) >= 3
but it replies
Incorrect syntax near the keyword 'join'.
Incorrect syntax near the keyword 'as'.
I'm a begginner here and in the sql, so i dont exactly know how to combine my previous 'filtr' and current join with date
I'll not tell you the solution, but give you some pseudo-code and you figure out how to code it in SQL-
a) You should restrict your data for just 14 days.
b) Now, make groupings by User and find the count of records/lines present (for each User).
c) Now, again do a filter check to find users whose count of records is greater than 3.
Now, tell us which SQL keywords will be used for each points above.
I think something like
select p.user_id
from posts p
join (select user_id, xdate start_date, date_add(xdate, interval 14 day) end_date
from posts) r
on p.user_id = r.user_id and p.xdate between r.start_date and r.end_date
group by user_id, start_date
having count(*) >= 3
can help. It may not be the best possible solution, but it works.
Check it on SQL Fiddle
If you just want to select users by id you may try
Select id_post, date from yourtable where user = 2 order by id DESC limit 10;
You should have Colum called id with auto increment so new posts will have higher id so when it's sorted in descending it will start with post with higher id also you should have index on that id colum auto increment and index
If you don't want to use the above method then you will do that with date range like this
$date = gmdate() - (3600*24); 24 is 24 hours past
Select id_post, title from mutable where add_date > 'value of $date'
In both cases you should have index on user id
The second query is what you need but you should get the date from the equation first then apply it to the query
First, I think you mean user 1 not 2.
In MySQL 8+, this is pretty easy. If you want the first such post:
select t.*
from (select t.*,
lead(date, 2) over (partition by user order by date) as next_date2
from t
) t
where next_date2 <= date + interval 14 day;

mySQL GROUP, most recent

Here is the data set:
Person Status Date
Eric 1 1/1/2015
Eric 2 2/1/2015
Eric 3 3/1/2015
John 1 3/1/2015
John 2 2/1/2015
John 1 1/1/2015
I'd like to get the most recent date, and its correlated status, grouped by Person. I tried using a subquery to first identify the most recent date:
SELECT MAX(Date), Person FROM tbl1 GROUP BY Person
And then joining that back into the original table, so that by person I know which date is the most recent. But I'm struggling how to identify the most recent status. I just don't see the appropriate aggregator. Thanks.
select tbl1.*
from tbl1
join
(
SELECT Person, MAX(Date) as m_date
FROM tbl1
GROUP BY Person
) tmp on tbl1.Person = tmp.Person
and tbl1.date = tmp.m_date

Ignore Group if LIMIT is not reached in MySQL

I am working on a rather tricky SQL for my level of knowledge. I have searched and searched for an answer but haven't came across anything. Hopefully someone can shed some light on this.
How can you stop SQL from outputting group of rows if the limit set is not reached?
For example -
Data
Fruits Ordered Date
Orange 4 2015-05-01
Orange 2 2015-05-01
Orange 20 2015-05-01
Apple 30 2015-05-02
Apple 40 2015-05-02
Apple 24 2015-05-02
Apple 19 2015-05-02
Apple 22 2015-05-02
From the data I would like to select and group by Date, but only have a LIMIT of 5.
If there isn't five rows in that group, I want SQL to ignore that group.
So If I did a SUM of all ordered values for each Date Group and SQL ignored the group that didn't consist of 5 values the desired results would look like the following
Desired Result
Fruits SUM(Ordered) Date
Apple 117 2015-05-02
Hope this makes sense, please ask any questions if required!
You can use the having clause to filter out the groups you don't need, keeping only the groups where there are more than 4 dates:
SELECT Fruits, SUM(Ordered), Date
FROM table
GROUP BY Date
HAVING COUNT(Date) > 4
select Fruits,sum(Ordered),Date from Table
group by Fruits, Date
where Fruits in (select Fruits from Table
group by Fruits having count(*) >= 5)
I think you want something like this:
SELECT
Fruits, SUM(Ordered), Date
FROM (
SELECT
*,
CASE WHEN (SELECT COUNT(*) FROM t ti WHERE ti.Fruits = t.Fruits) < 5 THEN Ordered END As gID
FROM t) dt
GROUP BY
Fruits, gID
Actually you need to use your PK column instead of Ordered in the CASE like this:
CASE WHEN (SELECT COUNT(*) FROM t ti WHERE ti.Fruits = t.Fruits) < 5 THEN `PK` END As gID