Get Start and End Time in Sql - sql

I have three Shifts in my office.How i can get name of current running shift using Sql Query ?
Table Description is as given below
Id, Name, startTime, hours
1, Shift1, 7:00 am, 8
2, Shift2, 3:00 pm, 8
3, Shift3, 11:00 pm, 8
Thanks in Advance

This is quite a top-level question, so I'm going to give you a top-level answer, rather than writing the code for you, because that way you'll have the tools to solve other problems in future.
I would approach this in 3 stages:
Write a query that selects the end time of each shift based on the startTime and hours columns, i.e. "what time is X hours after time Y". The exact function to use depends which DBMS you use (MySQL, PostgreSQL, MS SQL Server, SQLite, etc), but is likely to be called something like date_add.
Find out how to get the current time in your DBMS (e.g. now(), getdate(), CURRENT_TIME)
Write a WHERE clause that returns rows where a time is between two other times. (Hint: BETWEEN is a keyword in SQL.) Start simple with something you know will always be true, like "2:00 is between 1:00 and 3:00".
Put these together, and you can build the query you wanted: select rows where the current time is between the startTime and the calculated end time.

For SQL Server I think:
select Id, Name, startTime, hours
from table
where
convert(time, getdate()) >= startTime
and convert(time, getdate()) < DATEADD(HH, hours, startTime)
if startTime column type is time.
EDIT
I strongly suggest to change the column to Time
If this cannot happen consider the solution below:
select convert( time, '6:00 am' )
-- result 06:00:00.0000000
select convert( time, '6:00 pm' )
-- result 18:00:00.0000000
So:
create view MyTableView as
select
Id,
Name,
StartTime = convert( time, startTime ),
EndTime = DATEADD(HH, hours, convert( time, startTime ) ),
ShiftDuration = hours
from
MyTable
UPDATE for 24h shift span
select
Id,
Name,
StartTime,
EndTime,
ShiftDuration
from
MyTableView
where
(
( StartTime < EndTime )
and ( convert(time, getdate()) >= StartTime )
and ( convert(time, getdate()) < EndTime )
)
or
(
( StartTime >= EndTime )
and ( convert(time, getdate()) >= StartTime )
and ( convert(time, getdate()) > EndTime )
)

You didn't specify your DBMS, so this is ANSI SQL:
select *
from (
select id, name, start_time, start_time + interval '1' hour * hours as end_Time
from shifts
) t
where current_time between start_time and end_time;
SQLFiddle example: http://sqlfiddle.com/#!15/f5428/1

Related

SQL query SELECT time intervals

I'm trying to SELECT all the rows from a SQL database which are between an hour interval, for every day.
The datetime column is called "Dt" and has the following datetime format: 2019-10-17 16:03:43
I'd like to extract all the rows from this table where the Dt was between 22:00:00 and 02:00:00, for everyday.
SELECT *
FROM MY_TABLE
WHERE "Dt" BETWEEN '*-*- 22:00:00' AND '*-*- 02:00:00';
where * should be any...
Thanks for your support!
EDIT: I forgot to mention: I'm using the integrated SQL interpreter from DB Browser for SQLite
You need to extract the time part of the date and compare that it is within the range. Since midnight is between 22 and 2, you will need to split it to two comparisons, time between 22 and 0 and between 0 and 2.
To see how to extract the time take a look at this question.
With Postgres, assuming dt is defined as timestamp you can do the following:
SELECT *
FROM MY_TABLE
WHERE "Dt" BETWEEN "Dt"::date + time '22:00:00' and ("Dt"::date + 1) + time '02:00:00'
Or if you want to exclude timestamps at precisely 02:00:00
SELECT *
FROM MY_TABLE
WHERE "Dt" >= "Dt"::date + time '22:00:00'
and "Dt" < ("Dt"::date + 1) + time '02:00:00'
select DT_time from (
select cast (substr(to_char(Dt,'dd-mm-yyyy HH:MM:SS'),12,2) as integer ) as DT_time from MY_TABLE )
where DT_time between 2 and 22;
between 22:00:00 and 02:00:00
means:
SELECT *
FROM MY_TABLE
WHERE
substr(Dt, 12) BETWEEN '22:00:00' AND '23:59:59'
OR
substr(Dt, 12) BETWEEN '00:00:00' AND '02:00:00'
This will work ::
SELECT *
FROM MY_TABLE
WHERE DATEPART(HOUR, Dt)>22
AND DATEPART(HOUR, Dt)<2
Update :
SELECT *
FROM MY_TABLE
WHERE Dt Between DATEADD (hour,22,DATEADD(day, DATEDIFF(day, 0, Dt), 0)) AND DATEADD (hour,2,DATEADD(day, DATEDIFF(day, -1, Dt), 0))
SELECT *
FROM MY_TABLE
WHERE DATEPART(HOUR, Dt)>22
OR DATEPART(HOUR, Dt)<2
Above query work for you..
1st one will check only for particular date and consecutive next date along with your time range.
But If you don't care about dates and only looking for time interval in particular hours then 2nd one is for you.
For SQLite :
SELECT *
FROM MY_TABLE
WHERE strftime('%H','Dt')>22
OR strftime('%H','Dt')<2

How to skip overlap intervals in the following query to get the accurate per day track time

I have a query (see SQL Fiddle) which calculates the total track time per day. It worked fine until I found that my data is not clean and it has some intervals overlapping (i.e. starttime is repeated in some cases).
There are 1440 minutes in a day and therefore the maximum track time should be 1440, but due to the overlapping intervals the track time exceeds 1440 minutes per day in some cases.
At the moment the query makes it 1440 if the sum exceeds 1440. But if a value is less than 1440 it still can be wrong.
For example
One interval is from 10:00 to 14:00.
Second interval is from 13:00 to 15:00.
End result is 4 + 2 = 6 hours, where hour between 13:00 and 14:00 is counted twice.
End result is 360 minutes, which is less than 1440, but it is not a
correct answer, because data is not correct.
I want some help to fix the query so that it skips overlaps and calculates the correct track time. Thanks
;WITH
CTE_Dates
AS
(
SELECT
Email
,CAST(MIN(StartTime) AS date) AS StartDate
,CAST(MAX(EndTime) AS date) AS EndDate
FROM track
GROUP BY Email
)
SELECT
CTE_Dates.Email
,DayStart AS xDate
-- if some intervals overlap, it is possible
-- to get SUM more than 1440 per day
-- truncate such values for now
,CASE
WHEN ISNULL(SUM(DATEDIFF(second, RangeStart, RangeEnd)) / 60, 0) > 1440
THEN 1440
ELSE ISNULL(SUM(DATEDIFF(second, RangeStart, RangeEnd)) / 60, 0)
END AS TrackMinutes
FROM
Numbers
CROSS JOIN CTE_Dates
CROSS APPLY
(
SELECT
DATEADD(day, Numbers.Number-1, CTE_Dates.StartDate) AS DayStart
,DATEADD(day, Numbers.Number, CTE_Dates.StartDate) AS DayEnd
) AS A_Date
OUTER APPLY
(
SELECT
-- MAX(DayStart, StartTime)
CASE WHEN DayStart > StartTime THEN DayStart ELSE StartTime END AS RangeStart
-- MIN(DayEnd, EndTime)
,CASE WHEN DayEnd < EndTime THEN DayEnd ELSE EndTime END AS RangeEnd
FROM track AS T
WHERE
T.Email = CTE_Dates.Email
AND T.StartTime < DayEnd
AND T.EndTime > DayStart
) AS A_Track
WHERE
Numbers.Number <= DATEDIFF(day, CTE_Dates.StartDate, CTE_Dates.EndDate)+1
GROUP BY DayStart, CTE_Dates.Email
ORDER BY DayStart;
This is a "gaps and islands" problem. I faked my own test data (since you didn't provide any), but I think it works. The key intuition is that all values within the same "island" (that is, contiguous time interval) will have the same difference from a row_number() column. If you want a little insight into it, do a raw select from the IntervalsByDay cte (as opposed to the subquery I have now); this will show you the islands calculated (with start and end points).
edit: I didn't see that you had a fiddle on the first go around. My answer has been changed to reflect your data and desired output
with i as (
select datediff(minute, '2013-01-01', StartTime) as s,
datediff(minute, '2013-01-01', EndTime) as e
from #track
), brokenDown as (
select distinct n.Number
from i
join dbadmin.dbo.Numbers as n
on n.Number >= i.s
and n.Number <= i.e
), brokenDownWithID as (
select Number, Number - row_number() over(order by Number) as IslandID,
cast(dateadd(minute, number, '2013-01-01') as date) as d
from brokenDown
), IntervalsByDay as (
select
dateadd(minute, min(number), '2013-01-01') as [IntervalStart],
dateadd(minute, max(number), '2013-01-01') as [IntervalEnd],
d,
max(Number) - min(Number) + 1 as [NumMinutes]
from brokenDownWithID
group by IslandID, d
)
select d, sum(NumMinutes) as NumMinutes
from IntervalsByDay
group by d
order by d

Comparing results with today's date?

Is there a way to use the Now() function in SQL to select values with today's date?
I was under the impression Now() would contain the time as well as date, but today's date would have the time set to 00:00:00 and therefore this would never match?
OK, lets do this properly. Select dates matching today, using indexes if available, with all the different date/time types present.
The principle here is the same in each case. We grab rows where the date column is on or after the most recent midnight (today's date with time 00:00:00), and before the next midnight (tomorrow's date with time 00:00:00, but excluding anything with that exact value).
For pure date types, we can do a simple comparison with today's date.
To keep things nice and fast, we're explicitly avoiding doing any manipulation on the dates stored in the DB (the LHS of the where clause in all the examples below). This would potentially trigger a full table scan as the date would have to be computed for every comparison. (This behaviour appears to vary by DBMS, YMMV).
MS SQL Server: (SQL Fiddle | db<>fiddle)
First, using DATE
select * from dates
where dte = CAST(CURRENT_TIMESTAMP AS DATE)
;
Now with DATETIME:
select * from datetimes
where dtm >= CAST(CURRENT_TIMESTAMP AS DATE)
and dtm < DATEADD(DD, 1, CAST(CURRENT_TIMESTAMP AS DATE))
;
Lastly with DATETIME2:
select * from datetimes2
where dtm2 >= CAST(CURRENT_TIMESTAMP AS DATE)
and dtm2 < DATEADD(DD, 1, CAST(CURRENT_TIMESTAMP AS DATE))
;
MySQL: (SQL Fiddle | db<>fiddle)
Using DATE:
select * from dates
where dte = cast(now() as date)
;
Using DATETIME:
select * from datetimes
where dtm >= cast((now()) as date)
and dtm < cast((now() + interval 1 day) as date)
;
PostgreSQL: (SQL Fiddle | db<>fiddle)
Using DATE:
select * from dates
where dte = current_date
;
Using TIMESTAMP WITHOUT TIME ZONE:
select * from timestamps
where ts >= 'today'
and ts < 'tomorrow'
;
Oracle: (SQL Fiddle)
Using DATE:
select to_char(dte, 'YYYY-MM-DD HH24:MI:SS') dte
from dates
where dte >= trunc(current_date)
and dte < trunc(current_date) + 1
;
Using TIMESTAMP:
select to_char(ts, 'YYYY-MM-DD HH24:MI:SS') ts
from timestamps
where ts >= trunc(current_date)
and ts < trunc(current_date) + 1
;
SQLite: (SQL Fiddle)
Using date strings:
select * from dates
where dte = (select date('now'))
;
Using date and time strings:
select dtm from datetimes
where dtm >= datetime(date('now'))
and dtm < datetime(date('now', '+1 day'))
;
Using unix timestamps:
select datetime(dtm, 'unixepoch', 'localtime') from datetimes
where dtm >= strftime('%s', date('now'))
and dtm < strftime('%s', date('now', '+1 day'))
;
Backup of SQL Fiddle code
There is no native Now() function in SQL Server so you should use:
select GETDATE() --2012-05-01 10:14:13.403
you can get day, month and year separately by doing:
select DAY(getdate()) --1
select month(getdate()) --5
select year(getdate()) --2012
if you are on sql server 2008, there is the DATE date time which has only the date part, not the time:
select cast (GETDATE() as DATE) --2012-05-01
Not sure what your asking!
However
SELECT GETDATE()
Will get you the current date and time
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
Will get you just the date with time set to 00:00:00
Just zero off the time element of the date. e.g.
SELECT DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)
I've used GetDate as that's an MSSQL function, as you've tagged, but Now() is probably MySQL or you're using the ODBC function call, still should work if you just replace one with the other.
Not sure exactly what you're trying to do, but it sounds like GETDATE() is what you're after. GETDATE() returns a datetime, but if you're not interested in the time component then you can cast to a date.
SELECT GETDATE()
SELECT CAST(GETDATE() AS DATE)
Building on the previous answers, please note an important point, you also need to manipulate your table column to ensure it does not contain the time fragment of the datetime datatype.
Below is a small sample script demonstrating the above:
select getdate()
--2012-05-01 12:06:51.413
select cast(getdate() as date)
--2012-05-01
--we're using sysobjects for the example
create table test (id int)
select * from sysobjects where cast(crdate as date) = cast(getdate() as date)
--resultset contains only objects created today
drop table test
I hope this helps.
EDIT:
Following #dwurf comment (thanks) about the effect the above example may have on performance, I would like to suggest the following instead.
We create a date range between today at midnight (start of day) and the last millisecond of the day (SQL server count up to .997, that's why I'm reducing 3 milliseconds). In this manner we avoid manipulating the left side and avoid the performance impact.
select getdate()
--2012-05-01 12:06:51.413
select dateadd(millisecond, -3, cast(cast(getdate()+1 as date) as datetime))
--2012-05-01 23:59:59.997
select cast(getdate() as date)
--2012-05-01
create table test (id int)
select * from sysobjects where crdate between cast(getdate() as date) and dateadd(millisecond, -3, cast(cast(getdate()+1 as date) as datetime))
--resultset contains only objects created today
drop table test
If you have a table with just a stored date (no time) and want to get those by "now", then you can do this:
SELECT * FROM tbl WHERE DATEDIFF(d, yourdate, GETDATE())=0
This results in rows which day difference is 0 (so today).
For me the query that is working, if I want to compare with DrawDate for example is:
CAST(DrawDate AS DATE) = CAST (GETDATE() as DATE)
This is comparing results with today's date.
or the whole query:
SELECT TOP (1000) *
FROM test
where DrawName != 'NULL' and CAST(DrawDate AS DATE) = CAST (GETDATE() as DATE)
order by id desc
You can try this sql code;
SELECT [column_1], [column_1], ...
FROM (your_table)
where date_format(record_date, '%e%c%Y') = date_format(now(), '%e%c%Y')
You can try:
WHERE created_date BETWEEN CURRENT_TIMESTAMP-180 AND CURRENT_TIMESTAMP
This worked for me:
SELECT * FROM table where date(column_date) = curdate()

SQL Greater than, Equal to AND Less Than

I want to create a query like the following, But im unsure of how to code it correctly,
I want it to return all bookings within 1 hour of a StartTime, Here is what i came up with:
SELECT BookingId, StartTime
FROM Booking
WHERE StartTime <=> 1.00
Is the possible? or Is there a way round it?
Everything ive found on the web hasn't been about using Greater than, Equal to and Less Than all in the same query.
Supposing you use sql server:
WHERE StartTime BETWEEN DATEADD(HOUR, -1, GetDate())
AND DATEADD(HOUR, 1, GetDate())
If start time is a datetime type then you can use something like
SELECT BookingId, StartTime
FROM Booking
WHERE StartTime >= '2012-03-08 00:00:00.000'
AND StartTime <= '2012-03-08 01:00:00.000'
Obviously you would want to use your own values for the times but this should give you everything in that 1 hour period inclusive of both the upper and lower limit.
You can use the GETDATE() function to get todays current date.
declare #starttime datetime = '2012-03-07 22:58:00'
SELECT BookingId, StartTime
FROM Booking
WHERE ABS( DATEDIFF( minute, StartTime, #starttime ) ) <= 60
Somthing like this should workL
SELECT BookingId, StartTime
FROM Booking
WHERE StartTime between dateadd(hour, -1, getdate()) and getdate()

Date Calculation Between two dates

I need some help doing a date calculation.
I have something that Expires every X number of days away from its Create Date
So, if the Create Date was 4/22 and the Expiration days were set to 10 it would expire
5/2, 5/12, 5/22, 6/1 etc...
I need to be able to tell people when their item is going to expire within 5 days
So for 5/2, I need to add this item to a count if the current date is between 4/27 and 5/2.
This is in SQL.
All we have are the RunDate, the CreateDate and the ExpirationDays
I've done the math calc to roughly get the Expiration date, but if it gets a remainder it's not helpful, and I don't want to skew anyone's answer by posting what I think it should be. I've tried quite a few ways and am getting a little desperate.
Any help would be greatly appreciated
EDIT:
I did the math for this and it looks like this
CreateDate + (((RunDate - CreateDate)/ExpireDays)*ExpireDays)) Between Rundate-1 and Rundate +5
But this gives me arithmetic overflow in SQL, so I'm not sure what to do...
In MySql you could do something
(ExpirationDays - (DATEDIFF(NOW(), CreateDate) % ExpirationDays)) > 5;
EDIT
For SQL Server you would do it a little different:
#expiringDays - (DATEDIFF(dd, ml.CreateDate, #date) % #expiringDays) > 5;
With Expirations As
(
Select Cast('2011-04-22' As datetime) As CreateDate, 10 As ExpirationDays
Union All
Select DateAdd( d, ExpirationDays, CreateDate ), ExpirationDays
From Expirations
Where CreateDate <= DateAdd(d,10,CURRENT_TIMESTAMP) --(arbitary end date)
)
Select *
From Expirations
Where CreateDate >= CURRENT_TIMESTAMP
And CreateDate <= DateAdd(d,5,CURRENT_TIMESTAMP)
Using similar logic to the math you used in your updated post:
With Expirations As
(
Select Cast('2011-04-22' As datetime) As CreateDate, 10 As ExpirationDays
Union All
Select DateAdd( d, ExpirationDays, CreateDate ), ExpirationDays
From Expirations
Where CreateDate <= DateAdd(d,10,CURRENT_TIMESTAMP) --(arbitary end date)
)
Select *
From Expirations
Where CreateDate >= DateAdd(d, -1, CURRENT_TIMESTAMP)
And CreateDate <= DateAdd(d, 5, CURRENT_TIMESTAMP)