Determining the length of a user's visit based on SQL timestamps - sql

I am divided between using a C# implementation and a pure SQL 2005/2008 implementation. I need to determine the length of usage based on timestamps of their last actions. My table contains "friendID" (uniqueIdentifier) and "lastAction" datetime. Here is an example:
Bob, 1:00 PM
Bob, 1:01 PM
Bob, 1:20 PM
Bob, 1:25 PM
Jack, 5:00 PM
Bob, 11:20 PM
I want to "time out" a user if they had 60 minutes of inactivity. If your suggestion works correctly, there should be 3 separate sessions from the data above. There is a long break between Bob's session that started at 1 PM and the one that started at 11:20 PM.
Correct results should be: Bob (duration 25 minutes), Jack (duration 0 minutes), Bob (duration 0 minutes)
How would you return those 3 rows using pure SQL or C#?
Thank you very much for your help, it is really needed here.

Here's a pure SQL example:
If you only need the start times of the session:
select u, t
from test a
where not exists (
select 1
from test b
where a.u = b.u
and b.t >= a.t - '60 minutes'::interval
and b.t
If you really need the duration of the session:
select a.u, a.t, c.t
from test a, test c
where not exists (
select 1
from test b
where a.u = b.u
and b.t >= a.t - '60 minutes'::interval
and b.t c.t)
and a.u = c.u
and a.t

It sounds like a simple problem, unless I'm misunderstanding the question:
select friendId, max(lastAction) 'lastAction'
from myTable
where lastAction >= dateadd(day, -1, getdate())
-- don't analyze data over 24 hours old
group by friendId
having max(lastAction) < dateadd(minute, -60, getdate())
This returns all friends who have had activity in the last 24 hours, but not in the last 60 minutes.

Record the start time of the first action in the session. Record the last time in the session as well. Look at te Globals.asax events. There should be something like OnSessionEnd (If anyone knows the exact event, please comment). When this happens, record the durration between start time and last time. If you are not using ASP.Net, then there should be equivalent events in WinForms.
Now, the easiest way to deal with the 60 minute timout is to just set it in the web.config. If you don't want to do that, then you will have to have some logic when you are saving your current date to handle this. Like, if the new current date is more than 60 minutes from the old one, then record the old durration and then reset the start and current dates to now.

Related

How to write query in Ruby to check certain time object is less than 1 hour or 3 hour

I have a Trip model in ruby which has start_at column and i need to get Trip object if start_at less than 1 hour or 3 hour (only i should get trip object when start_at is < 1hr or < 3hr not for < 2hr, < 4hr, ..... etc).
Note: I have Cron job which runs for every 15.minutes to get trip object as explained above.
Example: Assume i have a trip which start_at = 9:00 am and current time is 10:00 am i should get that trip object. Same goes for 3 hour also (start_at = 9:00 am and current time is 12:00 am)
^^ Except above two cases i should not get trip object, need to get only for less than 1hr or 3hr
This is what i tried
Trip.where("start_at < ? ", 1.hour.ago)
But above query returning trip object even if start_at < 2 hours ago, 4 hours ago, ..... blah blah
I am new to Ruby any help would be appreciated.
Thanks!
Trip.where(start_at: 2.hours.ago..1.hour.ago).or(Trip.where(start_at: 4.hours.ago..3.hour.ago))
You could use or query, or use array value:
Trip.where(start_at: [2.hours.ago..1.hour.ago, 4.hours.ago..3.hour.ago])

how to write a sql to calculate working hours minus rest time

I have a table of rest time in work shift
Begin end
12:00 12:30
17:30 18:30
Now I want to write a SQL to calculate actual working hours given the start and end time. For example if start at 9:00 and end at 15:00, the actual hours is 6-rest time=5.5 hours and if start at 9:00 and end at 20:00 the actual hours is 10 hours. How to write a procedure to check it in SQL server? Thx.
There are no schema details to work with here, which means the following SQL is generic and will have to be altered to fit your db.
SELECT
(datediff(minute, shiftStartTime, shiftEndTime)
- datediff(minute,breakStartTime,breakEndTime)) / 60.0
FROM yourTable
Notes:
If they can have multiple breaks, you need to sum up all the break times in minutes before deducting it from the shift period.
the calculation is specifically in minutes because the datediff counts the number of boundaries passed, so the date diff in hours between 11:59 and 12:01 is 1, even though the break is 2 minutes, you would count that as 1 hour if you count hours using the function.
If you can provide more schema details, we would be able to craft a more complete statement.
you can try below way using DATEDIFF
select *, CONVERT(time(7),DATEADD(s, DATEDIFF(s,S,E),'00:00:00')) from QQ
http://sqlfiddle.com/#!18/01213d/1
for your case column name will be
select *, CONVERT(time(7),DATEADD(s, DATEDIFF(s,Begin,end),'00:00:00')) from yourtable

Find the minute difference between 2 date time

I need to get the difference between 2 date time in minutes(Time difference in minutes). And the last difference will be calculated based on 6 PM of every date.
Sample data: need result of last column
User_Name Date Time difference in minutes
User 1 1/1/06 12:00 PM 30
user 2 1/1/06 12:30 PM 315
user 3 1/1/06 5:45 PM 15
Here the date will be always in same date and the last user date difference calculated based on default value 6PM. Assuming the dates of any user will not cross 6PM time.
Please suggest how to write the query for the same.
You could use the lead window function.
I assume your table is called mytable and the date column is mydate (it is a bad idea to call a column Date as it is a reserved word).
select user_name,
round((lead(mydate, 1, trunc(mydate)+18/24)
over (partition by trunc(mydate) order by mydate)
- mydate) *24*60) as difference
from mytable
I found the solution.. if its not correct let me know
SELECT User_name,created_date,
trunc(to_number((cast(nvl(lead (created_date,1) OVER (ORDER BY created_date),TRUNC(SYSDATE) + (19/24)) as date) - cast(created_date as date)))*24*60) as difference
FROM users;

Dynamic Timestamp DB2 SQL

Using DB2 SQL
I would like to query for records since 2:00 yesterday. I want a dynamic expression that frees me from having to manually enter the current date prior to running the query. The created_datetime attribute is of timestamp dataype.
For example:
select record_key, other_stuff
from table
where created_datetime > "2 o'clock PM yesterday"
Is this kind of dynamic timestamp comparison even possible? Eventually, I'd like to be able to do a window of time, which gets complicated!
select count(1)
from table
where created_datetime between "2 o'clock PM yesterday" and "2 o'clock PM today"
I am familiar with current date, but I am trying to conceptualize how I would leverage that. The following gets me close, but it includes everything 24 hours prior to whenever the query is run.
select count(1)
from table
where created_datetime between (currentdate - 1 day) and (currentdate # 2 o'clock PM)
I know this is some pretty basic territory, and I feel guilty posting this question, but my research has not turned up anything for me so far. I appreciate every ounce of time spent on my behalf.
Try these
select record_key, other_stuff
from table
where created_datetime > CURRENT DATE - 10 HOURS
select count(1)
from table
where created_datetime between (CURRENT DATE - 10 HOURS) and (CURRENT DATE + 14 HOURS)
select count(1)
from table
where created_datetime between (CURRENT DATE - 1 DAYS) and (CURRENT DATE + 14 HOURS)
From the IBM Dev Works Library : DB2 Basics: Fun with Dates and Times
There are heaps of samples there.
E.g.
You can also perform date and time calculations using, for lack of a
better term, English:
current date + 1 YEAR
current date + 3 YEARS + 2 MONTHS + 15 DAYS
current time + 5 HOURS - 3 MINUTES + 10 SECONDS
Try this with this Timestamp option in you where clause.
Below sample to query for between last 24 hours.
select
timestamp(CURRENT date - 1 days,(CURRENT time - 24 hours)),
timestamp(CURRENT date,CURRENT time )
FROM
sysibm.sysdummy1;

How do I compare overlapping values within a row?

I seem to have a problem with this SQL query:
SELECT * FROM appts
WHERE timeStart >='$timeStart'
AND timeEnd <='$timeEnd'
AND dayappt='$boatdate'
The time is formatted as military time. The logistics is that a boat rental can be reserved at 7am til 1pm or 9am til 1pm or 9am til 5pm. If there is an appt within that range, it should return appts but it has proven to be inconsistent. If I pick 9am til 1pm, it will ignore appts that started with 7am even though it overlaps 9am-1pm. If I pick 9 to 5, it will return nothing even though it should with the 7am to 1pm. How do I make a SQL statement that includes the whole range from timeStart to timeEnd including those that overlap?
Shahkalpesh answered the question with:
I think you need an OR.
SELECT * FROM appts
WHERE (timeStart >='$timeStart'
OR timeEnd <='$timeEnd')
AND dayappt='$boatdate'
I posted a comment that I consider this to be wrong, giving a pair of counter-examples:
This is plain wrong - #ShaneD is correct. For example, this will pick out a booking between 05:00 and 06:00 because the actual end time is less than any of the end times you ask about. It will also pick up rentals from 18:00 onwards, for the equivalent reason.
In a response to my comment, Shahkalpesh requested:
Could you post a separate reply with data & input parameters with expected output?
Fair enough - yes. Slightly edited, the question says:
The logic is that a boat rental can be reserved
from 7am until 1pm, or
from 9am until 1pm, or
from 9am until 5pm.
If there is an appointment within that range, it should return appointments but it has proven to be inconsistent. If I pick 9am until 1pm, ...
Enough background. We can ignore the date of the appointments, and just consider the times. I'm assuming that there is an easy way to limit the times recorded to hh:mm format; not all DBMS actually provide that, but the extension to handle hh:mm:ss is trivial.
Appointments
Row timeStart timeEnd Note
1 07:00 13:00 First valid range
2 09:00 13:00 Second valid range
3 09:00 17:00 Third valid range
4 14:00 17:00 First plausibly valid range
5 05:00 06:00 First probably invalid range
6 18:00 22:30 Second probably invalid range
Given a search for appointments overlapping the range 09:00 - 13:00, Shahkalpesh's (simplified) query becomes:
SELECT * FROM Appointments
WHERE (timeStart >= '09:00' OR timeEnd <= '13:00')
This will return all six rows of data. However, only rows 1, 2, 3 overlap the time period 09:00 - 13:00. If rows 1, 2, and 3 are the only valid representative appointment values, then Shahkalpesh's query produces the correct answer. However, if the row 4 (which I think is plausibly valid) is permitted, then it should not be returned. Similarly, rows 5 and 6 - if present - should not be returned. [Actually, assuming timeStart <= timeEnd for all rows in the table (and there are no NULL values to mess things up), we can see that Shahkalpesh's query will return ANY row of data for the 09:00-13:00 query because either the start time of the row is greater 09:00 or the end time is less than 13:00 or both. This is tantamount to writing 1 = 1 or any other tautology in the WHERE clause.]
If we consider ShaneD's query (as simplified):
SELECT * FROM Appointments
WHERE timeStart <= '13:00' AND timeEnd >= '09:00'
we see that it also selects rows 1, 2, and 3, but it rejects rows 4 (because timeStart > '13:00'), 5 (because timeEnd < '09:00') and 6 (because timeStart > '13:00'). This expression is an archetypal example of how to select rows which 'overlap', counting 'meets' and 'met by' (see "Allen's Interval Algebra", for instance) as overlapping. Changing '>=' and '<=' alters the set of intervals counted as overlapping.
The correct check would look like this:
SELECT * FROM appts
WHERE timeStart <='$timeEnd'
AND timeEnd >='$timeStart'
AND dayappt='$boatdate'
Other good explanations have been given but I'll go ahead and update it with an alternative explanation of how I visualize this myself. Most people are looking for each possible overlap, considering two time periods, they are trying to think of each combination of start and end that can make an appointment overlap. I think about it as when do two time periods not overlap which for some reason is easier for me.
Say the time period I am checking for is today, I want to find any time period that does not overlap today. There are really only two scenarios for that, either the time period starts after today (PeriodStart > EndOfToday) or the time period ends before today (PeriodEnd < StartOfToday).
Given that we havea simple test for not overlapping:
(PeriodStart > EndOfToday) OR (PeriodEnd < StartOfToday)
A quick flip around and you have a simple test for overlap:
(PeriodStart <= EndOfToday) AND (PeriodEnd >= StartOfToday)
-Shane
Thanks Shane, Shahkalpesh, and Jonathan.
I actually overlooked the fact that Shane "swapped" the variables (I was still using timeStart<=$timeStart when it should be timeStart <= $timeEnd). I ran with the modified statement as Jonathan/Shane suggested and it works. As Jonathan did point out, I did obviously missed out some time ranges that I should have tested against.
Now with Jonathan's explanation, I now get a better picture of my mistake is and it's helpful.
I think you need an OR.
SELECT * FROM appts
WHERE (timeStart >='$timeStart'
OR timeEnd &LT;='$timeEnd')
AND dayappt='$boatdate'
Assuming each record cares about only a specific day.
i.e. Boats rented don't run across more than 1 day.