id Bus arrival time
1 6:30
2 7:00
3 9:00
4 10:00
5 15:00
6 16:00
If one bus comes at 6:40 then nearest time should be 6:30
If bus comes at 9:35 nearest time should be 10:00 like wise I need the solution as a T-SQL query
Thanks In Advance,
Anil
declare #checkTime time = '6:40'
select top 1 * from schedule
order by ABS(DATEDIFF(Second, #checkTime, busArrivalTime))
SQLFIDDLE
you can do something like :
DECLARE #TIME TIME = '6:45'
DECLARE #TEMP TABLE(ID int,start time);
insert into #temp values(1, '6:30')
insert into #temp values(1, '7:00')
insert into #temp values(1, '9:00')
insert into #temp values(1, '10:00')
insert into #temp values(1, '15:00')
insert into #temp values(1, '6:30')
insert into #temp values(1, '16:00')
SELECT top(1)start ,ABS(DATEDIFF(MINUTE , #TIME ,START )) as diff
FROM #TEMP
order by diff
Related
I'm working with the following table in SQL Server, which captures the start & end date/time for which an employee worked:
EMP_NO RECORD_DATE START_TIME END_TIME
123456 2020-07-04 10:00:00.0000000 14:30:00.0000000
I need to transpose the date/time values, so that it generates incremental records at 30 minute intervals with the Date/time values concatenated:
Expected Result:
EMP_NO SHIFT_WORKED
123456 2020-07-04 10:00
123456 2020-07-04 10:30
123456 2020-07-04 11:00
123456 2020-07-04 11:30
123456 2020-07-04 12:00
123456 2020-07-04 12:30
123456 2020-07-04 13:00
123456 2020-07-04 13:30
123456 2020-07-04 14:00
Sample code:
CREATE TABLE #HOURS (
EMP_NO INT NOT NULL,
RECORD_DATE DATETIME ,
START_TIME TIME NOT NULL,
END_TIME TIME NOT NULL
)
INSERT INTO #HOURS
VALUES (123456 ,' 2020-07-04',' 10:00',' 14:30')
A tally table will help you here. (I prefer to call it an "integers table"). This is just a table of integers. You can either actually have one persisted somewhere in the database, or create one "one the fly" with a CTE. There are a lot of different ways to create such a thing, some faster than others!
Once you have a tally table, you can generate any values that can be mathematically derived from that. In your case, datetime values in 30 minute increments. You can then join that onto your date range. Here's one way which generates a tally table as a CTE
with integers as (
select top 1000 -- as many as you need
i = -1 + row_number() over (order by a.number) -- start from 0
from master..spt_values a
cross join master..spt_values b
)
select h.emp_no,
shift_worked = dateadd(minute, i * 30, t.startdt)
from #hours h
cross apply ( -- this cross apply just makes the join to integers easier to read
select startdt = h.record_Date + cast(h.start_Time as datetime),
enddt = h.record_date + cast(h.end_time as datetime)
) t
join integers i on dateadd(minute, i * 30, t.startdt) < t.enddt
you can do this:
CREATE TABLE temp (EMP_NO INT ,SHIFT_WORKED datetime)
DECLARE #START_TIME TIME,#END_TIME TIME,#shift TIME,#emp int
SELECT #START_TIME=START_TIME,#END_TIME=END_TIME,#emp=EMP_NO FROM #HOURS
SET #shift=#START_TIME
WHILE DATEADD(MINUTE, 30, #shift) <=#END_TIME
BEGIN
INSERT INTO temp VALUES(#EMP,#shift)
SET #Shift = DATEADD(MINUTE, 30, #shift)
END
I have tbl_emp like that:
empid
1
2
3
4
And tbl_att like that:
empid workingdate
1 2017-05-11
2 2017-05-13
3 2017-05-14
...........
...........
I have a job in SQL Server agent to execute step every Sunday and I want that job to insert a row for each empid with that day into tbl_att. Let's say Sunday is 2017-05-22 so I want it like that:
empid workingdate
1 2017-05-22
2 2017-05-22
3 2017-05-22
It means that I want it to insert into tbl_att for all empid with the same day (task execution day), so can anyone guide me a query that I need to put into my step command?
Try this,
INSERT INTO tbl_att SELECT empid,CAST(GETDATE() AS DATE) FROM tbl_emp;
insert into tbl_att (empid, workingdate)
Select empid,cast(getdate() as date) from tbl_emp
As you run the job on every Sunday, above query will insert the data as per your expectation I believe. FYI, But it depends on the system date
Hope it helps you
CREATE TABLE #tbl_att (empid INT,workingdate DATE)
CREATE TABLE #EmpidTab (empid INT)
INSERT INTO #EmpidTab
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4
SELECT * FROM #EmpidTab
INSERT INTO #EmpidTab
SELECT 5
INSERT INTO #tbl_att
SELECT Empid
,Getdate() AS workingdate
FROM #EmpidTab i
WHERE NOT EXISTS (
SELECT 1
FROM #tbl_att t
WHERE t.empid = i.Empid
) --Eliminate duplicte insertion of empid's
SELECT ##ROWCOUNT AS NoRowsInserted
SELECT *
FROM #tbl_att
stuck on a project. I wrote this code in sql server which finds the duplicate date matches for a staff member, but I'm stuck when trying to expand it to narrow it down to when the time ranges overlap each other also.
So there is a table called 'Rosters' with columns 'StaffID', 'Date', 'Start', 'End'
SELECT
y.[Date],y.StaffID,y.Start,y.[End]
FROM Rosters y
INNER JOIN (SELECT
[Date],StaffID, COUNT(*) AS CountOf
FROM Rosters
GROUP BY [Date],StaffID
HAVING COUNT(*)>1)
dd ON y.[Date]=dd.[Date] and y.StaffID=dd.StaffID
It returns all duplicate dates for each staff member, I wish to add the logic-
y.Start <= dd.[End] && dd.Start <= y.[End]
Is it possible with the way I'm currently doing it? Any help would be appreciated.
#TT. Sorry, below is probably a better visual explanation -
e.g This would be the roster table
ID Date Start End
1 01/01/2000 8:00 12:00
1 01/01/2000 9:00 11:00
2 01/01/2000 10:00 14:00
2 01/01/2000 8:00 9:00
3 01/01/2000 14:00 18:00
3 02/02/2002 13:00 19:00
And I'm trying to return what is below for the example as they are the only 2 rows that clash for ID, Date, and the Time range (start - end)
ID Date Start End
1 01/01/2000 8:00 12:00
1 01/01/2000 9:00 11:00
This is the logic that you would need to filter your results to overlapping time ranges, though I think this can be handled without your intermediate step of finding the duplicates. If you simply post your source table schema with some test data and your desired output, you will get a much better answer:
declare #t table (RowID int
,ID int
,DateValue date --\
,StartTime Time -- > Avoid using reserved words for your object names.
,EndTime Time --/
);
insert into #t values
(1,1, '01/01/2000', '8:00','12:00' )
,(2,1, '01/01/2000', '9:00','11:00' )
,(3,2, '01/01/2000', '10:00','14:00')
,(4,2, '01/01/2000', '8:00','9:00' )
,(5,3, '01/01/2000', '14:00','18:00')
,(6,3, '02/02/2002', '13:00','19:00');
select t1.*
from #t t1
inner join #t t2
on(t1.RowID <> t2.RowID -- If you don't have a unique ID for your rows, you will need to specify all columns so as no to match on the same row.
and t1.ID = t2.ID
and t1.DateValue = t2.DateValue
and t1.StartTime <= t2.EndTime
and t1.EndTime >= t2.StartTime
)
order by t1.RowID
Try this
with cte as
(
SELECT ROW_NUMBER() over (order by StaffID,Date,Start,End) as rno
,StaffID, Date, Start, End
FROM Rosters
)
select distinct t1.*
from cte t1
inner join cte t2
on(t1.rno <> t2.rno
and t1.StaffID = t2.StaffID
and t1.Date = t2.Date
and t1.Start <= t2.End
and t1.End >= t2.Start
)
order by t1.rno
Made some changes in #iamdave's Answer
If you use SQL Server 2012 up, you can try below script:
declare #roster table (StaffID int,[Date] date,[Start] Time,[End] Time);
insert into #roster values
(1, '01/01/2000', '9:00','11:00' )
,(1, '01/01/2000', '8:00','12:00' )
,(2, '01/01/2000', '10:00','14:00')
,(2, '01/01/2000', '8:00','9:00' )
,(3, '01/01/2000', '14:00','18:00')
,(3, '02/02/2002', '13:00','19:00');
SELECT t.StaffID,t.Date,t.Start,t.[End] FROM (
SELECT y.StaffID,y.Date,y.Start,y.[End]
,CASE WHEN y.[End] BETWEEN
LAG(y.Start)OVER(PARTITION BY y.StaffID,y.Date ORDER BY y.Start) AND LAG(y.[End])OVER(PARTITION BY y.StaffID,y.Date ORDER BY y.Start) THEN 1 ELSE 0 END
+CASE WHEN LEAD(y.[End])OVER(PARTITION BY y.StaffID,y.Date ORDER BY y.Start) BETWEEN y.Start AND y.[End] THEN 1 ELSE 0 END AS IsOverlap
,COUNT (0)OVER(PARTITION BY y.StaffID,y.Date) AS cnt
FROM #roster AS y
) t WHERE t.cnt>1 AND t.IsOverlap>0
StaffID Date Start End
----------- ---------- ---------------- ----------------
1 2000-01-01 08:00:00.0000000 12:00:00.0000000
1 2000-01-01 09:00:00.0000000 11:00:00.0000000
Please give me right answer for this question
This is the table time_names and its structure:
time_id time_name
------- ----------
1 5:00 AM
2 5:15 AM
3 5:30 AM
4 5:45 AM
5 6:00 AM
6 6:15 AM
... .....
... .....
70 10:15 PM
71 10:30 PM
72 10:45 PM
73 11:00 PM
74 11:15 PM
75 11:30 PM
76 11:45 PM
time_id is INT, time_name is varchar datatype.
Here I want show only 8:30 AM to 11:00 PM between all data
Please give me any query
Since you're on SQL Server 2008, you can simply cast the time_name to a TIME datatype:
SELECT time_id, time_name
FROM dbo.time_names
WHERE CAST(time_name AS TIME) BETWEEN '08:30 AM' AND '11:00 PM'
But seriously: if you store a time value - WHY aren't you using the appropriate TIME datatype for it??
select time_name between will not work, because it's string comparison. You have to use time_id or convert time, for example like this
select *
from time_names
where convert(nvarchar(8), convert(datetime, time_name, 109), 108) between '08:30' and '23:00'
Here I'm converting time from string to real date time and then converting it into 24 hours format, so you can use string compare.
you also can use time type
select *
from time_names
where convert(time, time_name, 109) between '08:30' and '23:00'
http://msdn.microsoft.com/en-us/library/ms187928.aspx
I also have to say that this table design looks really bad. You have to store date and time in the columns with apropriate types.
I´m not a SQL user but try to convert the 'time_name' to DateTime data type and use a select between DateTime1 AND DateTime2
You can use the following query
CREATE table #Time(
time_id int PRIMARY key,
time_name varchar(255))
INSERT INTO #Time values(1, '5:00 AM')
INSERT INTO #Time values(2, '5:15 AM')
INSERT INTO #Time values(3, '5:30 AM')
INSERT INTO #Time values(4, '5:45 AM')
INSERT INTO #Time values(5, '6:00 AM')
INSERT INTO #Time values(6, '6:15 AM')
INSERT INTO #Time values(7, '6:30 AM')
INSERT INTO #Time values(8, '6:45 AM')
select * from #Time
where CAST(time_name as datetime) between CAST('5:30 AM' as datetime) and CAST('6:00 AM' as datetime)
DROP TABLE #Time
I have data in the table like the following.
col1 col2 col3
--------------------------------------------------------
6/5/2010 18:05:00 6/2/2010 10:05:00 Null
6/8/2010 15:05:00 6/3/2010 10:45:00 6/5/2010 11:05:00
6/3/2010 15:05:00 Null 6/7/2010 12:05:00
6/1/2010 15:05:00 6/3/2010 10:45:00 6/1/2010 14:05:00
what my requirement is I want to update the date of there columns with single date without disturbing the time. say for example I want to update the table data with 6/1/2010 where the field data is not null. please let me know the query for updating the table data.
thanks & regards,
murali
I think this should work for you.
create table #t
(
col1 datetime
)
Insert Into #t
values ('2010-06-01 10:00:00')
Insert Into #t
values ('2010-06-06 11:00:00')
Insert Into #t
values ('2010-05-24 12:40:00')
Insert Into #t
values ('2010-05-07 13:00:00')
Insert Into #t
values (Null)
declare #newDate datetime
set #newDate = '2010-07-01'
update #t
Set col1 = DateAdd(day, DateDiff(day, col1, #newDate), Col1)
Where Col1 is not null
select * From #t
drop table #t
You may need to do it via SELECT statement as you dont need to run UPDATE statement each time new data are added to the table