Count unique days grouped by user - mysql

I have the following SQL table
|user|log_date |
| 2 |2016-06-23 10:55:52 |
| 2 |2016-06-23 10:55:54 |
| 2 |2016-06-24 10:53:54 |
| 2 |2016-06-24 10:54:54 |
and so on with many other users and log_dates. What I want is to check for whole month :
where left(log_date,7)="2016-06"
But I want to count one day only once per day. So the result for my table in this example should be :
|user|count of unique days|
| 2 | 2 |
and I want it to be grouped by users. So for every user in table I want to count unique days.
Can anybody give me a hint?

Writing the condition this way allows the use of an index...
SELECT t.user
, COUNT(DISTINCT DATE(t.log_date)) unique_days
FROM my_table t
WHERE t.log_date BETWEEN '2016-06-01 00:00:00' AND '2016-06-31 23:59:59' -- or t.log_date >= '2016-06-01 00:00:00' AND t.log_date < '2016-07-01 00:00:00'
GROUP
BY t.user;
(Not sure why Sagi deleted their answer after correcting it)

Try this:
select
user,
count(distinct day(log_date)) as `count of unique days`
from yourtable
where left(log_date, 7) = '2016-06'
group by user
SQLFiddle Demo

Related

Group by Day of Month

Say I have a table logins with just the bigint id ,a date_login of type datetime, and fk_user of type bigint. I need to select the first and last logins for each day of the month in the specified year.
I was guessing something like:
select *theDayOfTheMonth*,min(date_login), max(date_login)
from logins
where year(date_login) = *theYearInput* and
and fk_user = *theKeySpecified* and
month(date_login) = *theMonthInput*
group by *theDayOfTheMonth*
but I don't know how to group by that day of month. How can I do this?
You were close. It will look something like this:
SELECT DATE(date_login) as dayOfMonth, min(date_login), max(date_login)
FROM logins
WHERE year(date_login) = #theYearInput
and fk_user = #theKeySpecified
and month(date_login) = #theMonthInput
GROUP BY DATE(date_login)
Alternatively you might use the Day() function instead, which should still work because the query is limited to a single specific month via conditions in the WHERE clause:
SELECT DAY(date_login) as dayOfMonth, min(date_login), max(date_login)
FROM logins
WHERE year(date_login) = #theYearInput
and fk_user = #theKeySpecified
and month(date_login) = #theMonthInput
GROUP BY DAY(date_login)
Functionally, given these conditions the only difference between them is the format of the first column in the output. However, if you later need to expand across larger date ranges the first version will handle that better.
The function that you are looking for is DayOfMonth()
create table logins(
fk_user bigint,
date_login datetime);
insert into logins values
(1,'2022-01-01 09:00:00'),(1,'2022-01-01 18:00:00'),(1,'2022-01-02 08:00:00'),(1,'2022-01-02 16:00:00')
select
DayOfMonth(date_login) day,
min(date_login) first_login,
max(date_login) last_login
from logins
where year(date_login) = 2022
and fk_user = 1 and
month(date_login) = 1
group by DayOfMonth(date_login);
day | first_login | last_login
--: | :------------------ | :------------------
1 | 2022-01-01 09:00:00 | 2022-01-01 18:00:00
2 | 2022-01-02 08:00:00 | 2022-01-02 16:00:00
db<>fiddle here

mysql getting where clause weather the count is 0 or not

I wanted to show assigned_user_id in the Column User_ID whether the Meeting_Count is 0 or having value.
With below Query I'm getting only
+---------+---------------+
| User_ID | Meeting_Count |
+---------+---------------+
| NULL | 0 |
+---------+---------------+
SELECT
meeting.assigned_user_id AS User_ID,
COUNT(*) AS Meeting_Count
FROM meeting
WHERE meeting.assigned_user_id = '5c3e31bb4b708eeb5'
AND meeting.date_start >= NOW() - INTERVAL 60 DAY
My Requirement is to get as this,
+-------------------+---------------+
| User_ID | Meeting_Count |
+-------------------+---------------+
| 5c3e31bb4b708eeb5 | 0 |
+-------------------+---------------+
Can anyone help me on this. I'm still a learner.
The where clause filters out rows that do not belong to the given user, resulting in an empty resultset if no row at all matches. One workaround is to move the filtering within a conditional expression. In MySQL, you would phrase this as:
select
'5c3e31bb4b708eeb5' as user_id,
sum(assigned_user_id = '5c3e31bb4b708eeb5') as meeting_count
from meeting
where date_start >= now() - interval 60 day
If there is a possibility that the table contains no rows for the last 60 days, and you still want a result in that case, then you can take on step forward and move the date filtering to the sum() as well:
select
'5c3e31bb4b708eeb5' as user_id,
sum(assigned_user_id = '5c3e31bb4b708eeb5' and date_start >= now() - interval 60 day) as meeting_count
from meeting
This is guaranteed to always return one row.
It should be noted that conditional aggregation is by nature less efficient than filtering with a where clause.

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: query with condition on one-to-many table

I have a table with schema like this:
clients_actions
id | client_id | action | date_done
1 | 1 | ... | 1394785392
2 | 2 | ... | 1394786392
3 | 2 | ... | 1394787392
date_done can be set both in the past, and in the future from current unix timestamp. I need to select all 'forgotten' clients, which don't have date_done set in future (in all his actions) and last his action is older than 604800 seconds (7 days). Client can have many actions. And also, if it's possible, I need in the same query to select his last action (which is in past and more than 7 days old).
How can it be done?
One way to do it as
select * from clients_actions
where from_unixtime(date_done) < date_sub(now(),INTERVAL 7 day)
AND client_id
NOT IN
(
select client_id from
clients_actions
where from_unixtime(date_done) > now()
)
;
DEMO
In the demo I have added some data with future dates so that they can be ignored and just by getting data older than 7 days. You can do group by in case there are repeated data in your table.
Select client_id, action, MAX(date_done) from clients_actions
WHERE date_done < (UNIX_TIMESTAMP(SYSDATE() - 7)
AND id NOT IN (SELECT id FROM clients_actions
WHERE date_done > (UNIX_TIMESTAMP(SYSDATE()))
GROUP BY client_id;
For the first part you want a query that has Where date_done < SysDate - 7 days and client_id not in (select id from clients_actions where date_done > SysDate (also converted to UNIX). This says I want all records whose date_done is older than 7 days ago, but that don't have any actions due in the future.
the MAX and group by client_id limit it to only the latest record of those selected by client_id.
The following query will get you the desired result.
SELECT *
FROM clients_actions ca
INNER JOIN
(SELECT client_id, MAX(date_done) as date_done
FROM clients_actions
WHERE DATEDIFF(CURRENT_TIMESTAMP, FROM_UNIXTIME(date_done)) >= 7
GROUP BY client_id) latest_date
ON ca.client_id = latest_date.client_id AND ca.date_done = latest_date.date_done;

MySQL query help with grouping and adding

I have a table called user_logins which tracks user logins into the system. It has three columns, login_id, user_id, and login_time
login_id(INT) | user_id(INT) | login_time(TIMESTAMP)
------------------------------------------------------
1 | 4 | 2010-8-14 08:54:36
1 | 9 | 2010-8-16 08:56:36
1 | 9 | 2010-8-16 08:59:19
1 | 3 | 2010-8-16 09:00:24
1 | 1 | 2010-8-16 09:01:24
I am looking to write a query that will determine the number of unique logins for each day if that day has a login and only for the past 30 days from the current date. So for the output should look like this
logins(INT) | login_date(DATE)
---------------------------
1 | 2010-8-14
3 | 2010-8-16
in the result table 2010-8-16 only has 3 because the user_id 9 logged in twice that day and him logging into the system only counts as 1 login for that day. I am only looking for unique logins for a particular day. Remember I only want the past 30 days so its like a snapshot of the last month of user logins for a system.
I have attempted to create the query with little success what I have so far is this,
SELECT
DATE(login_time) as login_date,
COUNT(login_time) as logins
FROM
user_logins
WHERE
login_time > (SELECT DATE(SUBDATE(NOW())-1)) FROM DUAL)
AND
login_time < LAST_DAY(NOW())
GROUP BY FLOOR(login_time/86400)
I know this is wrong and this returns all logins only starting from the beginning of the current month and doesn't group them correctly. Some direction on how to do this would be greatly appreciated. Thank you
You need to use COUNT(DISTINCT ...):
SELECT
DATE(login_time) AS login_date,
COUNT(DISTINCT login_id) AS logins
FROM user_logins
WHERE login_time > NOW() - interval 30 day
GROUP BY DATE(login_time)
I was a little unsure what you wanted for your WHERE clause because your question seems to contradict itself. You may need to modify the WHERE clause depending on what you want.
As Mark suggests you can use COUNT(DISTINCT...
Alternatively:
SELECT login_day, COUNT(*)
FROM (
SELECT DATE_FORMAT(login_time, '%D %M %Y') AS login_day,
user_id
FROM user_logins
WHERE login_time>DATE_SUB(NOW(), INTERVAL 1 MONTH)
GROUP BY DATE_FORMAT(login_time, '%D %M %Y'),
user_id
)
GROUP BY login_day