Working with time of integer format using SQL - sql-server-2012

Could anyone support me to query with SQL Server 2012?
I have an entity for recording the time from daily booking system:
CREATE TABLE tblBooking
(
Id varchar(36) NOT NULL,
stationID varchar(36) NOT NULL,
roomId varchar(36) NOT NULL,
Leader varchar(15) NOT NULL,
Title nvarchar(50) NOT NULL,
meeting_Date int NOT NULL,
meeting_time int NOT NULL,
end_time int NOT NULL,
CONSTRAINT tblBooking_pk PRIMARY KEY (Id)
);
I tried to record the date and time in integer format with yyyyMMdd & H24:m formats
I want to book a room by empty slot and avoid these cases
Case 1:
Queue 1: booked at 08:00 - 11:00 -> status is success
Queue 2: will book at 09:00 - 10:00 -> status is not success or
Queue 2: will book at 08:00 - 11:00 -> status is not success (duplicate)
Case 2:
Queue 1: booked at 09:00 - 10:30 -> status is success
Queue 2: will book at 08:00 - 09:30 -> status is not success or
Queue 2: will book at 09:30 - 11:00 -> status is not success
As of the above cases I have not enough idea to verify coming transaction.
I tried to use >/< operators or BETWEEN but it's will have issue coming to case #1
This is my effort so far:
SELECT *
FROM tblBooking a
WHERE 1 = 1
AND a.roomId = 'IT234'
AND a.meeting_date = 20220215
AND a.meeting_time > 900 AND a.end_time < 1000
/* AND ((a.meeting_time > 900 OR a.meeting_time < 1000)
OR (a.end_time > 900 Or a.end_time < 1000)) */
Could anyone help to improve my query?
Thank you in advance!

Related

SQLite - Convert time (like 08:00) into integer

please, I read that best way (and most effective) is saving time as a SMALLINT (INTEGER in real). It is true? I'm building application which using SQLite3 Database and DB size must be small and calculate with date and time (time specially) must be most effective.
I Have this table:
CREATE TABLE events (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
time_start SMALLINT NOT NULL ,
time_end SMALLINT NOT NULL,
message_code VARCHAR(64) NOT NULL,
FOREIGN KEY (message_code) REFERENCES messages (message_code),
CHECK ((time_start BETWEEN 0 AND 1440) AND (time_end between 0 and 1440) AND (message_code <> ''))
);
But in fact I want inserting values in real time like 08:20 because no one wants calculate that 8 hours is 480 minutes + 20 = 500 minutes.
It is possible how to convert ('08:20') into number 500? I don't need calculate with seconds.
Or do do you think that using DATETIME is a better way?
PS: It's a scheduler which listing a events like a agenda in outlook e.g.
Thank you very much for any advice.
Best regards
SQLite has no DateTime data type.
You can store values as char(5) strings - this will only take up five bytes. You can compare these values directly.
sqlite> select '08:20' > '08:30';
0
sqlite> select '08:20' = '08:30';
0
sqlite> select '08:20' < '08:30';
1
0 is false, 1 is true.
And also with the built-in time function:
sqlite> select time('08:20') = time('now');
sqlite> select time('08:20') = time('2018-01-01 05:30:59');

How does one retrieve records with all days in date range covered?

Imagine you have something like a action rental or hotel scenario where a unit can have rates for specific days and they can be available or not. I want to be able to search all my units for a specified arrival date and departure date to only bring back units that meet the whole time period.
Lets say each unit has a rate table similar to below
PropertyID Rate Start_Date End_Date Status Type
1 400 03/12/18 03/13/18 Available Daily
1 400 03/13/18 03/14/18 Available Daily
1 400 03/14/18 03/15/18 Available Daily
1 400 03/15/18 03/16/18 Reserved Daily
1 400 03/16/18 03/17/18 Available Daily
1 400 03/17/18 03/18/18 Available Daily
1 400 03/18/18 03/19/18 Available Daily
1 900 03/12/18 03/19/18 Blocked Weekly
Daily rates are split into each day due to the fact you can book a day at any time while a weekly rate needs the full range available. In the above case, it turns out that I would NOT be able to rent the weekly rate as the 15 day is reserved and that is part of the weekly rate.
If someone were to search that they wanted to stay 3/12/18 to 3/19/18 and assuming all of the above was available, I have it it doing in a store procedure (pseudo code)
Select stuff
From Property
Inner Join PropertyRate pr
where pr.Start_Date = #arrrivalDate And pr.End_Date = #departureDate
This would get me the property back because the weekly rate fits. However if the weekly rate was removed and it was only the daily rates, this would not return this property. Assuming all the statuses were available for the daily rates, this property should return because each day of the period specified is available.
How can I check if each day in the requested date range has an available date for that time period?
If it matters, this is Microsoft SQL Server 2014.
Edit 1:
It was requested for table definitions. Here is the property rate table create script:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PropertyRates]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[PropertyRates](
[property_rate_id] [int] IDENTITY(1,1) NOT NULL,
[rate_details_id] [int] NOT NULL,
[property_id] [int] NOT NULL,
[rate] [money] NOT NULL,
[start_date] [date] NOT NULL,
[end_date] [date] NOT NULL,
[status] [varchar](20) NOT NULL,
[created] [datetime] NOT NULL,
CONSTRAINT [PK_PropertyRates] PRIMARY KEY CLUSTERED
(
[property_rate_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_PADDING OFF
GO
I believe that is what was asked.
Edit 2:
I wasn't very clear on what I'm trying to do for an output. Since this SQL is used in a search function, I only want to return the SINGLE property record for the property if it has available rates on every day of the passed in search range. So the end SQL should just have the property record if the many rates for that property are available and cover every day in the passed in date range.
Also note, that besides daily and weekly rates, there are also other such as monthly, bi-monthly, daily 2 day min, etc but they all have the start and end date columns filled in.
So for the above example, for a stay from 3/12 to 3/19, I should NOT get the property back because there is no range of days covered by available because the weekly rate is blocked and the daily rate has a reserved in the middle. If the reserved rate changed to available, the property should be returned.
select propertyid,count(*)
from property
where count(*) = datediff(dd,#startenddate, #enddate)+1
and status='Available'
group by propertyid
This will calculate the number of days requested (datediff) and calculate if there are that number of days in the table that are available.
UNION ALL could be a good way to handle this:
DECLARE #ArrivalDate Date = '20180312'
DECLARE #DepartureDate Date = '20180319'
SELECT *
FROM myTable t1
JOIN (SELECT PropertyID, Type --Handle Weekly Availability
FROM myTable
WHERE Type = 'Weekly'
AND Status = 'Available'
AND Start_Date = #ArrivalDate
AND End_Date = #DepartureDate
UNION ALL
SELECT PropertyID, Type --Handle Daily Availability
FROM myTable
WHERE Type = 'Daily'
AND Status = 'Available'
AND Start_Date >= #ArrivalDate
AND End_Date <= #DepartureDate
GROUP BY PropertyID, Type
HAVING COUNT(DISTINCT Start_Date) = DATEDIFF(Day, #ArrivalDate, #DepartureDate)
) t2 ON t1.PropertyID = t2.PropertyID --JOIN back to retrieve other needed data
AND t1.Type = t2.Type
Fiddle example here
Note, I changed the sample data to have one valid daily and one valid weekly example.

Check Time Range Lapse in Other Time Range

I have a Time In and Time Out and there is a time range defined for Lunch Breakfast and Dinner. What i want is to Subtract these times from the attendance time (Time In And Time Out).
The sample data is
Attendance Table Data
EMPID 1095
TimeIN 2017-03-01 08:52:45.000
TimeOut 2017-03-01 19:59:18.000
The Mess Timings are
type StartTime EndTime
BreakFast 06:30:39 10:00:39
Dinner 19:00:39 21:00:39
Lunch 12:00:23 15:00:23
What i need is to subtract these mess timings from the actual attendance time to get actual employee duty time.
Thanks.
This approach utilises a numbers table to create a lookup table of all the seconds between your #TimeIn and #TimeOut values. This will work for periods covering multiple days, albeit with some severe caveats:
Breakfast, Lunch and Dinner are at the same time every day.
Your #TimeIn and #TimeOut period doesn't get so big it overflows the int value that contains the number of seconds.
In that case you will need to either just use minutes or find a different method
Your return value is less than 24 hours.
In that case, just don't return the difference as a time data type and handle it accordingly.
declare #TimeIn datetime = '2017-03-01 08:52:45.000'
,#TimeOut datetime = '2017-03-01 19:59:18.000'
,#BStart time = '06:30:39'
,#BEnd time = '10:00:39'
,#LStart time = '12:00:23'
,#LEnd time = '15:00:23'
,#DStart time = '19:00:39'
,#DEnd time = '21:00:39';
-- Create numbers table then use it to build a table os seconds between TimeIn and TimeOut
with n(n) as (select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as n(n))
,s(s) as (select top (select datediff(s,#TimeIn,#TimeOut)+1) dateadd(s,row_number() over (order by (select 1))-1,#TimeIn) from n n1,n n2,n n3,n n4,n n5,n n6)
select cast(dateadd(s,count(1),0) as time) as s
from s
where s between #TimeIn and #TimeOut -- Return all seconds that aren't within Breakfast, Lunch or Dinner
and cast(s as time) not between #BStart and #BEnd
and cast(s as time) not between #LStart and #LEnd
and cast(s as time) not between #DStart and #DEnd
Which returns: 05:59:58.0000000
I have daily timings of mess in other table so i created a view and took all fields in front of daily attendance then using case statement to match the timings with Daily Attendance Time.
EmployeeID AttendanceDate ShiftID TimeIn TimeOut BreakOut BreakIn LeaveType TotalHours LeaveHours ATOThours DeductedHrs OTHours UserID AudtDate Reason SM SY OTDed DutyDed Mark Expr1 MARKL BreakFastStart BreakFastEnd LunchStart LunchEnd DinnerStart DinnerEnd
1095 2017-03-01 00:00:00.000 1 2017-03-01 08:52:45.000 2017-03-01 19:59:18.000 NULL NULL NULL 0 NULL 0 0 0 NULL NULL NULL 3 2017 NULL NULL NULL NULL NULL 2017-02-20 06:30:34.000 2017-02-20 09:30:34.000 2017-02-20 12:00:26.000 2017-02-20 15:00:26.000 2017-02-20 19:00:59.000 2017-02-20 21:00:59.000
For now it's good will check it's credibility with the passage of time.
Thanks For the support
You can also use the following script in the View OR in JOIN query of the tables. Note I got a different answer which I think is correct.
SELECT CONVERT(varchar, DATEADD(ss,
(DATEDIFF(ss,TimeIn, [TimeOut]) -
(
DATEDIFF(ss,[BreakFastStartTime], [BreakFastEndTime]) +
DATEDIFF(ss,[LunchStartTime], [LunchEndTime]) +
DATEDIFF(ss,[DinnerStartTime], [DinnerEndTime])
)
), 0), 108)
FROM [Attendance Data]
For your example, answer is 02:36:33

Calculating working time with overlapping events (SQL)

I have found similar queries on StackOverflow (e.g. Finding simultaneous events in a database between times) but nothing that matches exactly what I am after as far as I can tell so thought it OK to add as a new question.
I have a table that logs jobs (or "Activities"), with a start/end time for the job. I need to calculate working time (you can disregard non-working days, break times etc. as I have that covered). The complication is an individual can work on simultaneous jobs, overlapping at different points (the assumption is equal effort on simultaneous jobs), and the working time needs to reflect that. Minute accuracy is all that is required, not to the second.
Based on other suggestions I have this query, implemented as a table-valued function. It will look at each minute that activity is running, and if any other activities are running in the same period for the same person, and make calculations based on that. It works, but is very inefficient - taking over a minute to execute. Any ideas how I can do this more efficiently?
Running SQL 2005. I have done the obvious such as to add indexes on foreign keys by the way.
CREATE FUNCTION [dbo].[WorkActivity_WorkTimeCalculations] (#StartDate smalldatetime, #EndDate smalldatetime)
RETURNS #retActivity TABLE
(
ActivityID bigint PRIMARY KEY NOT NULL,
WorkMins decimal NOT NULL
)
/********************************************************************
Summary: Calculates the WORKING time on each activity running in a given date/time range
Remarks: Takes into account staff working simultaneously on jobs
(evenly distributes working time across simultaneous jobs)
Input Params: #StartDate - the start of the period to calculate
#EndDate - the end of the period to calculate
Output Params:
Returns: Recordset of activities and associated working time (minutes)
********************************************************************/
AS
BEGIN
-- any work activities still running use the overall end date as the activity's end date for the purpose of calculating
-- simulateneous jobs running
-- POPULATE A TEMP TABLE WITH EVERY MINUTE IN THE DATE RANGE
DECLARE #Minutes TABLE (MinuteDateTime smalldatetime NOT NULL)
;WITH cte AS (
SELECT #StartDate AS myDate
UNION ALL
SELECT DATEADD(minute,1,myDate)
FROM cte
WHERE DATEADD(minute,1,myDate) <= #EndDate
)
INSERT INTO #Minutes (MinuteDateTime)
SELECT myDate FROM cte
OPTION (MAXRECURSION 0)
-- POPULATE A TEMP TABLE WITH WORKLOAD PER EMPLOYEE PER MINUTE
DECLARE #JobsRunningByStaff TABLE (StaffID smallint NOT NULL, MinuteDateTime smalldatetime NOT NULL, JobsRunning decimal NOT NULL)
INSERT INTO #JobsRunningByStaff (StaffID, MinuteDateTime, JobsRunning)
SELECT wka_StaffID, MinuteDateTime, COUNT(DISTINCT wka_ItemID) JobsRunning
FROM dbo.WorkActivities
INNER JOIN #Minutes ON (MinuteDateTime BETWEEN wka_StartTime AND DATEADD(minute,-1,ISNULL(wka_EndTime,#EndDate)))
GROUP BY wka_StaffID, MinuteDateTime
-- FINALLY MAKE THE CALCULATIONS FOR EACH ACTIVITY
INSERT INTO #retActivity
SELECT wka_ActivityID, SUM(1/JobsRunning)WorkMins
FROM dbo.WorkActivities
INNER JOIN #JobsRunningByStaff ON (wka_StaffID = StaffID AND MinuteDateTime BETWEEN wka_StartTime AND DATEADD(minute,-1,ISNULL(wka_EndTime,#EndDate)))
GROUP BY wka_ActivityID
RETURN
END
Some example data (sorry for the poor formatting!)...
Source Data from WorkActivities table:
ACTIVITY ID | START TIME | END TIME | STAFF ID
1 | 03/03/2016 10:30 | 03/03/2016 10:50 | 1
2 | 03/03/2016 10:40 | 03/03/2016 11:00 | 1
And the desired results for a function call of SELECT * FROM dbo.WorkActivity_WorkTimeCalculations ('03-Mar-2016 10:30','03-Mar-2016 11:30'):
ACTIVITY ID | WORKMINS
1 | 25
2 | 15
So, the results take into account between 10:40 and 10:50 there are two jobs happening simultaneously, so calculates 5 mins working time on each over that period.
As suggested by posters, indexing made a significant difference - creating an index with wka_StartTime and wka_EndTime sorted it.
(sorry, couldn't see how to mark the comments made by others as an answer!)

copy first cell to second then add hours as int (DATEPART)

I have data in the table like the following.
TimeIn TimeOut
-------------------------------------
6/1/2010 09:00:00 Null
6/2/2010 09:00:00 6/2/2010 16:45:00
6/3/2010 10:05:00 Null
6/4/2010 07:30:00 6/4/2010 15:45:00
i have the stored procedure to find last activity with "not signd out" column
i have a stored procedure for copy a cell to other too ...
then, what i need, is to update [TimeOut] (if there's no time out)
via more elegant way like
UPDATE TimeOut SET DATEPART(HOUR, TimeOut) = DATEPART(HOUR, TimeIN) + 8
so the Whole idea was to
first check if last activity - Timeout Column is null
then if it is, sign TimeOut with max work hours allowed (8).
is there a simple way to do it ?
UPDATE
as to marc answer , this is the selection of find out if user didn't sign out
SELECT CASE WHEN [TimeOut] IS NULL THEN '' ELSE CONVERT(NVARCHAR,[TimeOut]) END FROM tblTime WHERE tId = ( SELECT MAX(tId) FROM tblTime WHERE UserId = 123
so i have the query that finds who did not sign out at last activity
then i only need to update that specific Row - field TimeOut
with hours of time in + 8
that was my question
Looks like you should use dateadd.
UPDATE TimeOut
SET TimeOut = DATEADD(HOUR, 8, TimeIN)
WHERE ....
This will set TimeOut to TimeIn plus eight hours.
add a where TimeOut IS NULL clause so it updates only the ones where the field actually is null?
UPDATE tblTime SET TimeOut = DATEADD(HOUR,8,TimeIn) WHERE tId = ( SELECT MAX(tId) FROM tblTime WHERE UserId = 1234)