MS SQL Server Query to Check if Hall is Booked - sql-server

This query is driving me crazy, any help is appreciated.
I have a table as follows:
CREATE TABLE Bookings
(
Id bigInt IDENTITY(1,1),
hallId bigInt,
startTime smallDateTime,
endTime smallDateTime
)
INSERT INTO Bookings
VALUES (1, '2022-10-03 08:00:00', '2022-10-03 10:00:00')
--Edit( One of my trials so far
DECLARE #startTime AS SmallDateTime = '2022-10-03 08:00:00'
DECLARE #endTime AS SmallDateTime = '2022-10-03 10:0:00'
DECLARE #hallId AS bigInt = 1
SELECT * FROM Bookings WHERE
startTime >= FORMAT(#startTime, 'yyyy-dd-MM HH:mm:ss') OR startTime <= FORMAT(#endTime, 'yyyy-dd-MM HH:mm:ss') AND
endTime >= FORMAT(#startTime, 'yyyy-dd-MM HH:mm:ss') OR endtime <= FORMAT(#endTime, 'yyyy-dd-MM HH:mm:ss')
AND hallId=#hallId
-- Also this Way
DECLARE #startTime AS SmallDateTime = '2022-03-10 08:00:00'
DECLARE #endTime AS SmallDateTime = '2022-03-10 10:0:00'
DECLARE #hallId AS bigInt = 1
SELECT * FROM Bookings WHERE
startTime >= #startTime OR startTime <= #endTime
AND
endTime >= #startTime OR endtime <= #endTime
AND hallId=#hallId
--Edit)
My Datetime format is 'yyyy-MM-dd HH:mm:ss' but it's records are entered in yyyy-dd-MM HH:mm:ss format
So what I want is a query that checks for 2 datetime ranges (say 2022-10-03 08:00:00 - 2022-10-03 10:00:00), if there is a match it returns the data otherwise it returns nothing.
My goal is to check if either of the startTime OR endTime falls within an existing Booking (e.g None of startTime or endTime can't be within '2022-10-03 08:00:00' up to '2022-10-03 10:00:00'), if found, the booking can't precede unless he/she has to alter. I tried between, but seems to work one way and fails another
It would be a plus if someone could check in separately that is to display a specific message/status for startTime and endTime (I mean if the startTime corresponds to existing Booking msg='Select a different start time' and if The endTime corresponds to existing Booking msg='Select a different end time'
Also I tried to check if the difference of startTime and endTime is less then 1 hour.
BWT, I'm using SQL Server 2014 Express

You can do INSERT...SELECT...WHERE NOT EXISTS, then check the rowcount afterwards. To compare for interval overlap, compare one start time with the other end, and the reverse.
Note that you should always specify column names for inserts, and pass values as parameters, not text.
INSERT INTO Bookings (hallId, startTime, endTime)
SELECT #hallId, #startTime, #endTime
WHERE NOT EXISTS (SELECT 1
FROM Bookings b WITH (UPDLOCK) -- needs UPDLOCK to prevent race conditions
WHERE b.hallId = #hallId
AND b.startTime < #endTime
AND b.endTime > #startTime
);
IF ##ROWCOUNT = 0
THROW 50001, N'Overlapping booking exists', 1;
You may want to change to <= if you don't want to allow two intervals to abut.

Thanks to who ever tried to help, I figured it out,
Sometimes all you need is to take a quick break.
I found out that smallDateTime data type was acting crazy, it was swapping the month and the day while inserting in the table
e.g if I Inserted 2022-03-15 20:00:00 it would be recorded as 2022-15-03 20:00:00 and vice-versa
So Here goes what worked for me, It may help someone in the nearer or far future
-- 2022-03-11 13:30:00, 2022-03-11 15:00:00 => sample data 1 in the table
-- 2022-03-11 09:30:00, 2022-03-11 12:30:00 => sample data 2 in the table
DECLARE #startTime AS SmallDateTime = '2022-03-11 15:01:00'
DECLARE #endTime AS SmallDateTime = '2022-03-11 19:30:00'
DECLARE #hallId AS bigInt = 1
SELECT * FROM Bookings WHERE
(startTime BETWEEN #startTime AND #endTime) OR
(endTime BETWEEN #startTime AND #endTime) AND hallId=#hallId

Related

Find out the quarter based on the financial year in SQL Server stored procedure

I have two tables, one is Period and the other is UserTarget.
Period table is:
QuarterNo StartDate EndDate
-----------------------------------------
1 2018-04-01 2018-06-30
2 2018-07-01 2018-09-30
3 2018-10-01 2018-12-31
4 2019-01-01 2019-03-31
UserTarget table is :
USERID YEAR QTR AMOUNT
---------------------------------
akshay 2019 1 200
Right now I am taking the qtr no from period table. Now I don't need take qtr no from period table. I want it from stored procedure based on year is entered in usertarget table
Existing stored procedure :
ALTER PROCEDURE [dbo].[GetQuarterlyTargetData]
#Userid VARCHAR(50)
AS
BEGIN
DECLARE #QuarterNumber VARCHAR(50)
DECLARE #SetTarget DECIMAL(10);
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SELECT
#QuarterNumber = p.QuarterNo,
#SetTarget = AMOUNT
FROM
PERIOD p
LEFT OUTER JOIN
USERTARGETS s ON p.QuarterNo = s.QTR
WHERE
StartDate <= GETDATE() AND EndDate >= GETDATE()
SELECT
#StartDate = StartDate,
#EndDate = EndDate
FROM
PERIOD
WHERE
QuarterNo = #QuarterNumber
From this procedure I am getting the start date and end date for quarter but I don't want to modify in period table every time when I want to check previous years data.
I believe that the term you are looking for is fiscal year. It's where the company year is different than the calendar year.
Note that many people recommend using a lookup table instead of calculating it. Date matches can be difficult for SQL to optimize.
Here's one way to do it. Finding the fiscal year and quarter would probably be good to put in a table function.
DECLARE #userTarget TABLE (UserId VARCHAR(20), Year INT, Quarter INT, Amount INT)
INSERT INTO #userTarget
VALUES
('akshay', 2018, 4, 150)
,('akshay', 2019, 1, 200)
SELECT
s.UserId
,s.Amount
,FY.FiscalYear
,FQ.FiscalQuarter
FROM
(
SELECT
--DATEFROMPARTS(2019, 2, 23)
GETDATE()
AS reportDate
) AS ReportDate
CROSS APPLY (
SELECT
CASE WHEN MONTH(ReportDate.reportDate) < 4 THEN YEAR(ReportDate.reportDate) - 1 -- Fiscal Year begins in April
ELSE YEAR(ReportDate.reportDate)
END AS FiscalYear
) AS FY
CROSS APPLY (
SELECT
DATEDIFF(QUARTER, DATEFROMPARTS(FY.FiscalYear, 4, 1), ReportDate.reportDate) + 1 AS FiscalQuarter
) AS FQ
INNER JOIN #userTarget s
ON s.Year = FY.FiscalYear
AND s.Quarter = FQ.FiscalQuarter
Also, be careful with end dates. last_day >= GETDATE() does not include the last day. Take as an example the end of last quarter, it would calculate it as '2019-03-31 00:00' >= '2019-03-31 08:20' which is false when you want it to be true.
After thinking I come up to this solutions
ALTER PROCEDURE [dbo].[Dashboard_GetQuarterlyTargetData]
#Userid varchar(50)
AS
Begin
DECLARE #QuarterNumber varchar(50)
DECLARE #SetTarget decimal(10);
DECLARE #AchievedTarget decimal(10);
DECLARE #TargetProgress decimal(10);
DECLARE #RemainingTarget decimal(10);
DECLARE #StartDate Date
DECLARE #EndDate Date
DECLARE #Year as int
Select #QuarterNumber = QTR,#Year=YEAR,#SetTarget=AMOUNT from USERTARGETS where USERID=#Userid
if(#QuarterNumber = 1)
begin
SELECT #StartDate = DATEFROMPARTS(#year,4,1), #EndDate=DATEFROMPARTS(#year,6,30)
End
else if(#QuarterNumber = 2)
begin
SELECT #StartDate = DATEFROMPARTS(#year,7,1), #EndDate=DATEFROMPARTS(#year,9,30)
End
else if(#QuarterNumber = 3)
begin
SELECT #StartDate = DATEFROMPARTS(#year,10,1), #EndDate=DATEFROMPARTS(#year,12,31)
End
else if(#QuarterNumber = 4)
begin
SELECT #StartDate = DATEFROMPARTS(#year,1,1), #EndDate=DATEFROMPARTS(#year,3,31)
End

SQL Server - DECLARE SET is taking too much time to execute than hardcoding the parameters in where condition

I have a simple select statement of a CTE where I have Declared and SET values before the WITH and I'm fetching data for a single day which would be having nearly 200,000 rows of data. If I execute that query, it is taking more time(not completed in 10 minutes). But If I remove those DECLARE, SET and hardcoded those input values in WHERE condition, the results are shown in 15 SECONDS.
This table has nearly 350 million rows of data with Proper Indexing of Primary Key columns.
What could be the possibility of this slowness?
Actual Query
DECLARE #StartTime DATETIME
DECLARE #EndTime DATETIME
DECLARE #ApplicationName VARCHAR(100)
SET #StartTime = '2018-12-10'
SET #EndTime = '2018-12-10'
SET #Applicationname = 'APPNAME'
;WITH TOTAL as (
SELECT * FROM TABLE WHERE DATETIME >= + #StartTime + '00:00:01' AND
DATETIME <= + #EndTime + '23:59:59'
AND APPLICATIONID=(SELECT APPLICATIONID FROM APPLICATION WHERE ApplicationName=#Applicationname
)
SELECT * FROM TOTAL
After Change
SELECT * FROM TABLE WHERE DATETIME >= '2018-12-10 00:00:01' AND
DATETIME <= '2018-12-10 23:59:59'
AND APPLICATIONID=(SELECT APPLICATIONID FROM APPLICATION WHERE ApplicationName='APPNAME'
Actually the DB has an SP with Long query, here I have provided the first CTE table only and the same kind of table conditions applicable to my rest of the CTE tables. If I get a clue for this slowness, I would fix the rest of my queries.
Since SQL server have to compile the variables StartTime and EndTime for each record on the TABLE for filtering, it takes longer. if you do something like the following:
DECLARE #StartTime DATETIME
DECLARE #EndTime DATETIME
DECLARE #ApplicationName VARCHAR(100)
SET #StartTime = '2018-12-10 00:00:01'
SET #EndTime = '2018-12-10 23:59:59'
SET #Applicationname = 'APPNAME'
SELECT *
FROM TABLE
WHERE DATETIME >= #StartTime AND DATETIME <= #EndTime
AND APPLICATIONID=(SELECT APPLICATIONID FROM APPLICATION WHERE
ApplicationName=#Applicationname
By doing this, you are reducing the load at the filtering time and doing pre-computing the required fixed variables.

Simple select query not working with 'AND' operator

I am working on a timetable and so I want to run a query which performs a check in the database to see all classes between a certain StartTime and EndTime. The user will select a start and end time for a class which will be stored in a label as a DateTime format 02/03/2017 00:00:00.
I want to run a query to check for a class so I want to use the selected start time to see if class is greater or equal to this start date but less than the next day 03/03/2017 00:00:00. The below query works fine but I will be using parameterised values.
My current query is:
SELECT * FROM Class WHERE (StartTime >='02/03/2017 00:00:00') AND ( EndTime <= '03/03/2017 00:00:00' )
My desired query with parameters:
SELECT * FROM Class WHERE (StartTime >='#StartTime') AND ( EndTime <= '#EndTime' )
You have quotes around the #StartTime and #EndTime. Remove those, so something like below should give you the correct results.
declare
#StartTime datetime = '2017-03-02 00:00:00.000',
#EndTime datetime = '2017-03-03 00:00:00.000'
SELECT * FROM Class WHERE (StartTime >=#StartTime) AND ( EndTime <= #EndTime )
Also to address your new requirement of
I just want to increment the value of the start time by 1 day
here is the code
declare
#StartTime datetime = '2017-03-02 00:00:00.000'
-- Add 1 day to start time to get the end date.
declare
#EndTime datetime = dateadd(day, 1, #StartTime)
SELECT * FROM Class WHERE (StartTime >=#StartTime) AND ( EndTime <= #EndTime )
Try without the single quotes:
SELECT * FROM Class WHERE (StartTime >=#StartTime) AND ( EndTime <= #EndTime )
you can declare StartTime and EndTime and your request be:
SELECT * FROM Class WHERE (StartTime >=#StartTime) AND ( EndTime <= #EndTime )
You must remove the quotes
SELECT * FROM Class WHERE (StartTime >=#StartTime) AND ( EndTime <= #EndTime )
Your query tries to parse a date out of the string "#EndTime"
declare #startTime datetime;
declare #endTime datetime;
set #startTime = cast(getdate() as date); -- sets start time to start of current day
set #endTime = dateadd(day,1,#startTime); -- sets end date to one day past start date
SELECT * FROM Class WHERE (StartTime >=#StartTime) AND ( EndTime < #EndTime ) -- use < for value to be less than next day

Creating a time dimension with specific dates on SQL

I'm making an analysis project on football transfers. I have a model with one Fact Table called FactTransfers and I need to link it to a time dimension but i need a specific range of dates, namely the dates where it's possible to transfer players (from June 1st to September 1st and from January 1st to January 31st).
I have seen some posts related to the matter but they all have code and attributes that I don't need.
Basically what i want is:
Date as primary key,
Day of the month,
Name of the month,
Transfer window (summer or winter),
Year.
I'm not too familiarized with sql code and I have spent hours trying to figure it out without the results I need.
Thank you in advance for all your help!
Here is the code to create and populate your Dim table for Dates. Hope this helps.
CREATE TABLE [dbo].[DimDate]
(
[DateKey] INT primary key,
[Date] DATETIME,
[DayofMonth] TINYINT, -- Field will hold day number of Month
[NameofMonth] VARCHAR(9),--January, February etc
[TransferWindow] VARCHAR(20), -- Summer & Winter
)
--Specify Start Date and End date here
--Value of Start Date Must be Less than Your End Date
DECLARE #StartDate DATETIME = '01/01/2015' --Starting value of Date Range
DECLARE #EndDate DATETIME = '12/31/2025' --End Value of Date Range
DECLARE #CurrentDate AS DATETIME = #StartDate
WHILE #CurrentDate < #EndDate
BEGIN
INSERT INTO [dbo].[DimDate]
SELECT
CONVERT (char(8),#CurrentDate,112) as DateKey,
#CurrentDate AS Date,
DATEPART(DD, #CurrentDate) AS [DayOfMonth],
DATENAME(MM, #CurrentDate) AS [MonthName],
CASE WHEN (MONTH(#CurrentDate) BETWEEN 6 AND 8) OR ( MONTH(#CurrentDate) =9 AND DATEPART(DD, #CurrentDate)=1) THEN 'Summer'
WHEN MONTH(#CurrentDate) =1 THEN 'Winter'
ELSE ''
END AS [TransferWindow]
SET #CurrentDate = DATEADD(DD, 1, #CurrentDate)
END
SELECT * FROM [DimDate]
--DROP TABLE [DimDate]

How do I calculate total minutes between start and end times?

How do I calculate total minutes between start and end times? The Start/End times columns are nvarchar and I am declaring them as datetime. I'm not sure if that is my first step or not, I am new to SQL and to declaring.
The final goal is to take Total Minutes, subtract Lunch and Recess (both are minutes) and then multiply by 5 to get total instructional minutes for the week per school.
DECLARE #StartTime datetime, #Endtime datetime
SELECT --[School]
[GradeLevel]
,[StartTime]
,[EndTime]
,(#Endtime - #StartTime) AS 'TotalMinutes'
,[Lunch]
,[Resess]
,[Passing]
FROM [dbo].[StartEndTimes]
Current Output:
GradeLevel StartTime EndTime TotalMinutes Lunch Resess Passing
2-5 7:50 14:20 NULL 20 10 NULL
K-5 7:45 14:20 NULL 20 10 NULL
K-5 7:50 14:20 NULL 20 10 NULL
Maybe something like this is what you want?
select (datediff(minute, starttime, endtime) -lunch -recess) * 5 AS TotalInstruct
from YourTable
If you want to sum it up for all rows then try:
select sum((datediff(minute, starttime, endtime) -lunch -recess) * 5) AS TotalInstruct
from YourTable
If you want to get the number of hours per school you would have to include the schoolfield in the query and use it in the group byclause, and then the query becomes this:
select school, sum((datediff(minute, starttime, endtime) -lunch -recess) * 5) AS TotalInstruct
from YourTable
group by school
Sample SQL Fiddle for the above queries.
If all you want is to find the difference between two dates then you can use DATEDIFF function (http://msdn.microsoft.com/en-us/library/ms189794.aspx)
Example:
DECLARE #startdate datetime2
SET #startdate = '2007-05-05 12:10:09.3312722';
DECLARE #enddate datetime2 = '2007-05-04 12:10:09.3312722';
SELECT DATEDIFF(MINUTE, #enddate, #startdate);
If however your values are in string format you need to convert them prior to passing them to the DATEDIFF function.
Example:
DECLARE #starttexttime nvarchar(100)
SET #starttexttime = '7:50'
DECLARE #starttime datetime2
SET #starttime = CONVERT(datetime2, #starttexttime, 0)
DECLARE #endtexttime nvarchar(100)
SET #endtexttime = '17:50'
DECLARE #endtime datetime2
SET #endtime = CONVERT(datetime2, #endtexttime, 0)
SELECT DATEDIFF(MINUTE, #starttime, #endtime);

Resources