I'm trying to figure out a way to perform a query which will obtain all data greater than six months old, without any data that is newer. I will see if I can appropriately summarize:
select u.USER_FirstName, u.USER_LastName,
u.USER_LastSession, c.Login_Name
FROM USER u
JOIN Customer c
ON u.USER_Customer_Identity=c.Customer_Identity
Where u.USER_LastSession < getdate()-180
Order by USER_LastSession
This is what I've found on SO so far, but the issue lies in that the USER.USER_LastSession records values for each log in (so some Customer.Login_Name values are unnecessary to return). I only want the ones which are greater than six months, with no result returned if they are also recorded at time less than six months. Example data:
USER_LastSession Login_Name
2012-08-29 21:33:30.000 TEST/TEST
2012-12-25 13:12:23.346 EXAMPLE/EXAMPLE
2013-10-30 17:13:45.000 TEST/TEST
I would not want to return TEST/TEST, since there is data in the past six months. I would, however, like to return EXAMPLE/EXAMPLE, since it only has data that is older than six months. I imagine there is probably something that I have overlooked - please forgive me if there is already an answer up for this (I was only able to find a "get older than six months" reply). Any and all help is greatly appreciated!
SELECT ...
FROM User u
JOIN Customer c ON u.USER_Customer_Identity=c.Customer_Identity
WHERE u.USER_Customer_Identity NOT IN
(SELECT USER_Customer_Identity
FROM User
WHERE USER_LastSession >= getdate() - 180)
ORDER BY USER_LastSession
with cte as (
select Login_Name, max(USER_LastSession) LastSession
FROM USER u
JOIN Customer c
ON u.USER_Customer_Identity = c.Customer_Identity
group by Login_Name
)
select *
from cte
where LastSession < getdate()-180
Related
Frontend dev here trying to get a query working.
A bit of context, we have a site where users can keep track of time and our goal is to get them to 1000 hours of time tracked.
For this we have:
a pretty default users table, with a column track_outdoors (0 or 1, since they can enable or disable it) and a meta column (json field)
A timers table, where each row has a total_time column
What I want to do is select all users who:
Have tracking enabled (track_outdoors = 1),
Do not have MORE than 1000 hours total_time tracked,
Have not received the reminder email (check if meta column has 'ac_outdoors_outdoors_reminder_sent_at')
Where the last time they tracked time was more than 2 weeks ago
I've got the basic part done, which is retrieving the users who have enabled tracking, together with their total time tracked:
SELECT
u.id,
u.firstname,
u.track_outdoors,
SUM(t.total_time) AS total
FROM
users AS u
LEFT JOIN timers AS t ON u.id = t.user_id
WHERE
u.track_outdoors = 1
AND JSON_EXTRACT(u.meta, '$.ac_outdoors_outdoors_reminder_sent_at') IS NULL
GROUP BY
u.id
Now the two parts I'm having trouble with is using the sum to check if the total_time is smaller than 1000 and checking if the last time tracking was more than two weeks ago.
Apparently I cant use the SUM inside of the WHERE statement.
I tried searching on how to do a where last relationship is x time ago, but all I find is how to query records x days ago. (It needs to be the latest record x days ago, if that makes sense).
I think for the SUM in the WHERE statement I might need to use a subquery, but I'm not sure if that's true or how I'm supposed to do that. For the 2 weeks ago check, I understand how to check where the date is two weeks ago but not how to check that for the latest record for the user.
Any help would be much appreciated!
Thanks to the comment/answer provided by #Akina I was able to finish my query.
The result is:
SELECT
u.id,
u.firstname,
u.track_outdoors,
SUM(t.total_time) AS total
FROM
users AS u
LEFT JOIN timers AS t ON u.id = t.user_id
WHERE
u.track_outdoors = 1
AND JSON_EXTRACT(u.meta, '$.ac_outdoors_outdoors_reminder_sent_at') IS NULL
GROUP BY
u.id
HAVING total < 1000 AND MAX( t.created_at ) < CURRENT_DATE - INTERVAL 2 WEEK
So I needed to use HAVING for checking the total and MAX to check for the date of the tracker to be more than two weeks ago.
I am making a covid log db for easy contact tracing.
these are my tables
log_tbl (fk_UserID, fk_EstID, log_date, log_time)
est_tbl (EstID, EstName)
user_tbl (User_ID, Name, Address, MobileNumber)
I wanted to write a statement that shows when and where an individual (User_ID)
enters an Establishment (EstID),
SELECT l.*
FROM log_tbl l
WHERE (l.EstID, l.log_date) IN (SELECT l2.EstID, l2.log_date
FROM log_tbl l2
WHERE l2.User_ID = 'LIN78JFF5WG'
);
[Result of Query]1
this currently works,
but it still has to be filterd by +-2 hours based on the time the when User_ID was logged on log_tbl, so that it would narrow down result when first query would spit out 1000 logs. Because these Results will be Contacted, and to reduce Costs, it needs to be narrowed down to less than 50%.
So, table below should not include first 2 and last one because it doesn't fit with 1, the date, and 2 the time, in relation to the searched userLIN78JFF5WG
[Unfiltered Result]2
FROM log_tbl
WHERE User_ID = 'LIN78JFF5WG'
AND (BETWEEN subtime(log_tbl.log_time, '02:00:00') AND addtime(log_tbl.log_time, '02:00:00'
I know this is wrong, but I don't have any idea how to join the two queries
and result should include
EstID, Name, Address, MobileNumber, log_date, log_time sorted by Date
Imagine it like this,
There are 3 baskets full of tomatoes,
2 of the baskets have rotten tomatoes inside.
Do you throw away the whole basket full of tomatoes?
No.. you select the rotten tomato, and others close to it, and throw them away.
I need that for the DB, instead of Getting Result for the Whole Day,
I only need the People who are in close contact with The Target user.
is it possible to do this on mysql? I have to use mysql because of reasons..
Here I include the data sample fiddle:
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=050b2103d3adf5828524f49066c12e74
MySQL supports window functions with the range window frame specification. I would suggest:
select l.*
from (select l.*,
sum(case when fk_UserID = 'LIN78JFF5WG' then 1 else 0 end) over
(partition by log_date
order by log_time
range between interval 2 hour preceding and interval 2 hour following
) as cnt_user
from log_tbl l
) l
where cnt_user > 0;
Here is a db<>fiddle.
You can then annotate the results would other columns from other tables to get your final result.
This should be much faster than alternative methods.
Note, however, that you have a flaw in this logic, because it is not checking four hours between 0:00-2:00 a.m. and 22:00-0:00. You can store the date/time in a single column to make it easier to get a more accurate list.
I am not fully understand your requirements.
but I write sample sql so that we can make it clear
select *,(select UNIX_TIMESTAMP(CONCAT(log_date," ",log_time)) as ts from log_tbl where fk_UserID='LIN78JFF5WG') as target_time
from
log_tbl as l
-- simple join query.to get intend information
left join user_tbl as u on (u.User_id=l.fk_UserID)
left join est_tbl as e on (l.fk_EstID=e.EstID)
-- mysql datediff only return day as unit.so we convert to timestamp to do the diff
where UNIX_TIMESTAMP(CONCAT(l.log_date," ",l.log_time)) - target_time between 60*60*2 and 60*60*2
-- solution two
-- but I suggest you divide it into two sql like this.
select UNIX_TIMESTAMP(CONCAT(log_date," ",log_time)) as ts from log_tbl where fk_UserID='LIN78JFF5WG';
-- we get the user log timestamp.and use it in next query
select *
from
log_tbl as l
-- simple join query.to get intend information
left join user_tbl as u on (u.User_id=l.fk_UserID)
left join est_tbl as e on (l.fk_EstID=e.EstID)
-- mysql datediff only return day as unit.so we convert to timestamp to do the diff
where UNIX_TIMESTAMP(CONCAT(l.log_date," ",l.log_time)) - [target_time(passed by code)] between 60*60*2 and 60*60*2
I'm working on a project where I search for a wifi signal (from cellphones etc). It detects every mac address that is around in the wifi sensors radius. This data is then sent from a server to a database, which uses a reporting tool to show statistics. This can be used in stores to study customer behavior.
This is what the data looks like:
The thing is, I want to know the time between entries, The problem is if a person stays for 10 minutes in the store it wil display alot of addresses, what I want to calculate is the difference between the visits. So what I need to do is count the time between the current day and the next day that they came.
I would then like to display this in a table like the one below.
current time | next time they came | Time between visist
-------------------------------------------------------------------
*current time* | *other day* | *Time between visits*
I have no idea how I should do this, abstract thinking is always welcome
P.s If there is any missing info, please comment. I'm new to the forums.
First of all you have to translate that time field into its readable date part
select date(from_unixtime(`time`)) from yourTable;
This value can be the joining criteria of a self join
select t1.address,
from_unixtime(t1.`time`),
min(from_unixtime(t2.`time`))
from yourTable t1
left join
yourTable t2
on t1.address = t2.address and
date(from_unixtime(t1.`time`)) < date(from_unixtime(t2.`time`))
group by t1.address, from_unixtime(t1.`time`)
This would get you, for each address and each visit time, the earliest visit time on a different day.
From there you could return the time difference
select tt.address,
tt.visit,
tt.next_visit,
timediff(coalesce(tt.next_visit, tt.visit), tt.visit) as `interval`
from (
select t1.address,
from_unixtime(t1.`time`) as visit,
min(from_unixtime(t2.`time`)) as next_visit
from yourTable t1
left join
yourTable t2
on t1.address = t2.address and
date(from_unixtime(t1.`time`)) < date(from_unixtime(t2.`time`))
group by t1.address, from_unixtime(t1.`time`)
) tt
The coalesce is to avoid having a null in the timediff function, which would happen for each address's last visit.
I have two tables in my database that I"m trying to use one Query to get data from both for a specific report.
Table one is "Movies" and it has these fields:
Movies_ID
Name
Season
Table two is "Boxoffice" sales income for each movie:
Boxoffice_ID
Movies_ID
Date
Amount
I want to run a query to compare the opening weekends for each movie in a given season and return them as one dataset with the amounts collected added together. So I want to take each movie and get the first three days of box office for each film and add them up so that I get back a query like this
Movie A, 49.1 Million
Movie B, 42.2 Million
Movie C, 29.5 Million
Please note the amount collected only needs to output the number and I'll take care of the formatting. I'm just having trouble figuring out how to only query the first three days of box office for each movie and adding them together.
I know I could run one query and get the movies with box office and then loop over that and re-query the database but I know that with a lot of movies that isn't the most efficient way of doing things. I'm not sure if there is a way to do all of this (first three days of each movie added together) in one query but I wanted to see if someone with more advanced knowledge could help me out.
SELECT a.Name, SUM(COALESCE(b.Amount,0)) totalAmount
FROM Movies a
LEFT JOIN BoxOffice b
ON a.Movies_ID = b.Movies_ID
WHERE b.date BETWEEN DATE_ADD(CURDATE(),INTERVAL -3 DAY) AND CURDATE()
GROUP BY a.Name
if the value of CURDATE() is 2012-11-06 (which is today), it will calculate from 2012-11-03 until 2012-11-06.
followup question, how do you calculate the date? by day? by week? or what?
UPDATE 1
SELECT a.Name, SUM(COALESCE(b.Amount,0)) totalAmount
FROM Movies a
LEFT JOIN BoxOffice b
ON a.Movies_ID = b.Movies_ID
LEFT JOIN
(
SELECT movies_ID, MIN(date) minDate
FROM BoxOffice
GROUP BY Movies_ID
) c ON a.Movies_ID = c.Movies_ID
WHERE DATE(b.date) BETWEEN DATE(c.minDate) AND
DATE(DATE_ADD(c.minDate,INTERVAL 3 DAY))
GROUP BY a.Name
just join the tables on Movies_ID and add WHERE with TIMEDIFF between issue date and Date being 3 days.
In rails 3 (also with meta_where gem if you feel like using it in your query), I got a really tricky query that I have been banging my head for:
Suppose I have two models, customers and purchases, customer have many purchases. Let's define customers with at least 2 purchases as "repeat_customer". I need to find the total number of repeat_customers by each day for the past 3 months, something like:
Date TotalRepeatCustomerCount
1/1/11 10 (10 repeat customers by the end of 1/1/11)
1/2/11 15 (5 more customer gained "repeat" status on this date)
1/3/11 16 (1 more customer gained "repeat" status on this date)
...
3/30/11 150
3/31/11 160
Basically I need to group customer count based on the date of creation of their second purchase, since that is when they "gain repeat status".
Certainly this can be achieved in ruby, something like:
Customer.includes(:purchases).all.select{|x| x.purchases.count >= 2 }.group_by{|x| x.purchases.second.created_at.to_date }.map{|date, customers| [date, customers.count]}
However, the above code will fire query on the same lines of Customer.all and Purchase.all, then do a bunch of calculation in ruby. I would much prefer doing selection, grouping and calculations in mysql, since it is not only much faster, it also reduces the bandwith from the database. In large databases, the code above is basically useless.
I have been trying for a while to conjure up the query in rails/active_record, but have no luck even with the nice meta_where gem. If I have to, I will accept a solution in pure mysql query as well.
Edited: I would cache it (or add a "repeat" field to customers), though only for this simplified problem. The criteria for repeat customer can change by the client at any point (2 purchases, 3 purchases, 4 purchases etc), so unfortunately I do have to calculate it on the spot.
SELECT p_date, COUNT(customers.id) FROM
(
SELECT p_date - INTERVAL 1 day p_date, customers.id
FROM
customers NATURAL JOIN purchases
JOIN (SELECT DISTINCT date(purchase_date) p_date FROM purchases) p_dates
WHERE purchases.purchase_date < p_date
GROUP BY p_date, customers.id
HAVING COUNT(purchases.id) >= 2
) a
GROUP BY p_date
I didn't test this in the slightest, so I hope it works. Also, I hope I understood what you are trying to accomplish.
But please note that you should not do this, it'll be too slow. Since the data never changes once the day is passed, just cache it for each day.