Can't get Sql Statement to work in a Case Statement - sql

I am trying to insert the Date and Day Of The Week into a table. The Table should contain 30 days excluding Sunday. I can not get the Insert inside the case statement to work. Any help would be greatly appreciated.
Declare #StartDate as Date = DateAdd(day,-30,GetDate())
Declare #DOW varchar(10)
Declare #adddaycnt int
Declare #RecsWrite int
Set #RecsWrite = 0
Set #adddaycnt = 0
While #RecsWrite <= 30
Begin
Select #DOW = DateName(dw,DateAdd(dw,#adddaycnt,#startDate))
Select Case When #DOW <> 'Sunday' then
Insert Into temp_ProdSaleInv (ProdDate,DOW)
Values(
Convert(varchar(10),DateAdd(day, #adddaycnt,#startDate),101),
DateName(dw,DateAdd(dw, #adddaycnt,#startDate)
)
)
End
Select Case When #DOW <> 'Sunday' then
Set #RecsWrite = #RecsWrite + 1
Set #adddaycnt = #adddaycnt + 1
Else
Set #adddaycnt = #adddaycnt + 1
End

The case statements won't work like you coded. Try this with IF instead.
Declare #StartDate as Date = DateAdd(day,-30,GetDate())
Declare #DOW varchar(10)
Declare #adddaycnt int
Declare #RecsWrite int
Set #RecsWrite = 0
Set #adddaycnt = 0
While #RecsWrite <= 30
Begin
Select #DOW = DateName(dw,DateAdd(dw,#adddaycnt,#startDate))
IF #DOW <> 'Sunday'
BEGIN
Insert Into temp_ProdSaleInv (ProdDate,DOW)
Values(
Convert(varchar(10),DateAdd(day, #adddaycnt,#startDate),101),
DateName(dw,DateAdd(dw, #adddaycnt,#startDate)
)
)
END
IF #DOW <> 'Sunday'
BEGIN
Set #RecsWrite = #RecsWrite + 1
Set #adddaycnt = #adddaycnt + 1
END
Else
BEGIN
Set #adddaycnt = #adddaycnt + 1
END
End

The CASE statement evaluates a list of conditions and returns one of multiple possible result expressions.
Instead, you are trying to actually run CRUD statements in the CASE statements.
Therefore, use something like IF conditions instead.

Related

TSQL CODE to set a value for a variable

I have a situation where I have a table with two dates lke startdate and enddate
and a procedure in which there is a variable #offset.
I need to write a tsql code for set the offset value as x when the current date falls in between the start date and enddate from the table. So I have to check the current date is in between the startdate and enddate from the table and then set the value. if not i have to set offset value as y.
I have to do that in the procedure it self.
Thanks for the help.
SET #offset = CASE WHEN GETDATE() BETWEEN #StartDate AND #EndDate THEN x ELSE y END
Maybe try this.
DECLARE #OffsetTable (placeholder INT)
INSERT INTO #OffsetTable
SELECT 1
FROM Table
WHERE GETDATE() BETWEEN StartDate AND EndDate
if (##rowcount > 0)
SET #offset = x
ELSE SET #offset = y
try this :
DECLARE #I Int;
DECLARE #Start Int =0;
DECLARE #End Int=0;
Set #I = Select Count(*) From YourTable;
While #I > 0
Begin
IF (GetDate() > select StartDate from yourTable where YourTableID=#I)
Set #Start = #Start + 1;
IF (GetDate() < select EndDate from yourTable where YourTableID=#I)
Set #End = #End + 1;
Set #I = #I -1;
End;
Set #I = Select Count(*) From YourTable;
If (#Satr = I) And (#End = I)
Set #Offset = X
Else Set #Offset = Y;
Note: Not tested.

Setting Variables in IF statements in SQL Server 2014

Msg 134, Level 15, State 1, Line 21
The variable name '#AsOfDate' has already been declared. Variable names must be unique within a query batch or stored procedure.
I am getting this error when running a set of IF statements. Ideally I would simply need to toggle my bit to 1 for the quarter I'm interested in and then execute my code. The IF statements would set the dates I need.
I have tried this with IF and ELSE IF, but neither seems to make a difference. Any suggestions on how I can do this would be greatly appreciated. Sadly I can't simply have it pick the quarter I'm in (or the one previous) as these reports may be requested at any time.
-------------------------
-- Choose Quarter --
-------------------------
DECLARE #Q1 BIT = 0
DECLARE #Q2 BIT = 0
DECLARE #Q3 BIT = 0
DECLARE #Q4 BIT = 0
DECLARE #Annual BIT = 0
-------------------------
--Q1
IF #Q1 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-03-31';
DECLARE #StartDate datetime = '2016-01-01'
END
--Q2
IF #Q2 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-06-30';
DECLARE #StartDate datetime = '2016-04-01'
END
--Q3
IF #Q3 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-09-30';
DECLARE #StartDate datetime = '2016-07-01'
END
--Q4
IF #Q4 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-12-31';
DECLARE #StartDate datetime = '2016-10-01'
END
-- ANNUAL
IF #Annual = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-12-31';
DECLARE #StartDate datetime = '2016-01-01'
END
-- Check to ensure a time period is set
IF (#Q1 = 0 AND #Q2 = 0 AND #Q3 = 0 AND #Q4 = 0 AND #ANNUAL = 0)
BEGIN
PRINT 'NO TIME SET'
END
-- Run Code with dates
ELSE
BEGIN
EDIT:
Disregard... actually reading my error and code clearly points to my declares being an issue not the setting of the variable... Solution is to declare the variables outside of my IF statements and SET them in the statement.
I was declaring in each IF statement instead of declaring prior to all the IF statements. Below is the updated version of the code.
DECLARE #ASOfDate DATETIME
DECLARE #StartDate DATETIME
-------------------------
-- Choose Quarter --
-------------------------
DECLARE #Q1 BIT = 0
DECLARE #Q2 BIT = 0
DECLARE #Q3 BIT = 0
DECLARE #Q4 BIT = 0
DECLARE #Anual BIT = 0
-------------------------
--Q1
IF #Q1 = '1'
BEGIN
SET #AsOfDate = '2016-03-31' ; SET #StartDate = '2016-01-01'
END
--Q2
IF #Q2 = '1'
BEGIN
SET #AsOfDate = '2016-06-30' ; SET #StartDate = '2016-04-01'
END
--Q3
IF #Q3 = '1'
BEGIN
SET #AsOfDate = '2016-09-30' ; SET #StartDate = '2016-07-01'
END
--Q4
IF #Q4 = '1'
BEGIN
SET #AsOfDate = '2016-12-31' ; SET #StartDate = '2016-10-01'
END
--ANUAL
IF #Anual = '1'
BEGIN
SET #AsOfDate = '2016-12-31' ; SET #StartDate = '2016-01-01'
END
-- Check to ensure a time period is set
IF (#Q1 = 0 AND #Q2 = 0 AND #Q3 = 0 AND #Q4 = 0 AND #ANUAL = 0)
BEGIN
PRINT 'NO TIME SET'
END
-- Run Code with dates
ELSE
BEGIN
Start of Actual Program using dates shown
END

Code error in a SQL Server While-If Loop

I know that there are other posts with code that solve my problem but I don't want to take another's code so I'm trying to do it by myself and I'm stuck with the month not increasing problem, so if anyone can help me with that mistake it will be awesome.
The problem is:
I have to populate the table Time from year 1990 to 2016 with all the months and days, I have already achieved that the code works and it populates correctly the years and the days but months increases to January (1) and then is not increasing so the table is filled with all months being January (LOL)
Here's my code:
create table Time
(
Year int,
Month int,
Day int
)
create procedure pTime
as
declare #year int, #month int, #day int;
set #year = 1990;
set #month = 12;
set #day = 10;
while(#year<=2016)
Begin
If(#day = 29)
Begin
set #month = #month + 1;
If(#month = 13)
Begin
set #month = 1;
set #day = 1;
set #year = #year + 1;
insert into Time values (#year, #month, #day);
End
End
else
Begin
If(#day = 29)
Begin
set #month = #month + 1;
set #day = 1;
insert into Time values (#year, #month, #day);
End
Else
Begin
insert into Time values (#year, #month, #day);
set #day = #day + 1;
End
End
End
Any idea where is my mistake or any suggestion?
I didn't look very closely for your mistake because SQL Server has some helpful date arithmetic functions. Here's simplified version of your stored procedure:
create procedure pTime
as
declare #theDate date = '12/10/1990', #days int = 0
while #theDate < '1/1/2016'
begin
insert into Time (Year, Month, Day) values (datepart(year, #theDate), datepart(month, #theDate), datepart(day, #theDate));
set #theDate = dateadd(day, 1, #theDate)
end
Another faster approach would be to use a tally table. Note the code below:
WITH
E(N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1),
iTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1 FROM E a,E b,E c,E d,E e),
dates(dt) AS
(
SELECT TOP(datediff(DAY,'19900101','20160101')) DATEADD(day,N,'19900101')
FROM iTally
)
--INSERT [time] --uncomment for the insert, leave commented to see what will be inserted
SELECT YEAR(dt), MONTH(dt), DAY(dt)
FROM dates;
Why do you need If(#year = 29) condition? In your code this block never will be executed. try this:
create procedure pTime
as
declare #year int, #month int, #day int;
set #year = 1990;
set #month = 12;
set #day = 10;
while(#year<=2016)
Begin
If(#day = 29)
Begin
set #month = #month + 1;
set #day = 1;
If(#month = 13)
Begin
set #month = 1;
set #year = #year + 1;
insert into Time values (#year, #month, #day);
End
End
else
Begin
If(#day = 29)
Begin
set #month = #month + 1;
set #day = 1;
insert into Time values (#year, #month, #day);
End
Else
Begin
insert into Time values (#year, #month, #day);
set #day = #day + 1;
End
End
End
I think first assignment set #day = 1; wasn't in right place. After increasing #month value you should set also #day to 1;

How to use IF statement in SQL Server 2005?

This is the scenario I would like to have in my INSERT in a stored procedure.
Tables:
tblRate
RateID (pk)
Rate money
Days int
isDailyRate bit
tblBooking
Totals money
In my vb app this is the statement. How would I translate this into T-SQL?
if !isDaily = True then
!Totals = (!Days * !Rate)
else
!Totals = !Rate
end if
This is my stored procedure:
Create PROCEDURE [dbo].[sp_tblBooking_Add]
(
#RateID bigint,
#Rate money,
#Days int,
#CheckOUT datetime
)
AS
BEGIN
--Below is the logic I want. I can't get the right syntax
--Declare #myTotals as money
--Declare #myCheckOut as DateTime
--if (Select isDailyRate FROM tblRates WHERE (RateID = #RateID)) = True THEN
-- set myTotals = (#Rate * #Days)
-- set #CheckOUT = DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) + #Days, '12:00')
--Else
-- set myTotals = #Rate
-- set #CheckOUT = GETDATE()
--End if
INSERT INTO tblBooking(Totals, CheckOUT)
VALUES(#myTotals, #myCheckOut);
END
Use the CASE expression:
INSERT INTO tblBooking (Totals, CheckOUT)
SELECT
CASE
WHEN idDailyRate = 1 THEN #Rate * #Days
ELSE #rate
END,
CASE
WHEN idDailyRate = 1 THEN DATEADD(DAY,
DATEDIFF(DAY, 0, GETDATE()) + #Days,
'12:00')
ELSE GETDATE()
END
FROM tblRates
WHERE RateID = #RateID;
Or, if they are scalar values, then you can select them into a variables and insert them instead of INSERT ... INTO ... SELECT.
Update 1
Like this:
Declare #myTotals as money;
Declare #myCheckOut as DateTime;
SELECT
#myTotals = CASE
WHEN idDailyRate = 1 THEN #Rate * #Days
ELSE #rate
END,
#myCheckOut = CASE
WHEN idDailyRate = 1 THEN DATEADD(DAY,
DATEDIFF(DAY, 0, GETDATE()) + #Days,
'12:00')
ELSE GETDATE()
END
FROM tblRates
WHERE RateID = #RateID;
INSERT INTO tblBooking (Totals, CheckOUT) VALUES(#myTotals, #myCheckOut );
But this will give you an error, if there is more than value returned from this table tblRates into those variables.

get DATEDIFF excluding weekends using sql server

I am using this query to get time taken.
SELECT DATEDIFF(dd, ActualStartDate, ActualCompletionDate) AS TimeTaken
FROM TableName
Now I want to exclude weekends and only include Mon-Fri as days counted.
Example query below, here are some details on how I solved it.
Using DATEDIFF(WK, ...) will give us the number of weeks between the 2 dates. SQL Server evaluates this as a difference between week numbers rather than based on the number of days. This is perfect, since we can use this to determine how many weekends passed between the dates.
So we can multiple that value by 2 to get the number of weekend days that occurred and subtract that from the DATEDIFF(dd, ...) to get the number of weekdays.
This doesn't behave 100% correctly when the start or end date falls on Sunday, though. So I added in some case logic at the end of the calculation to handle those instances.
You may also want to consider whether or not the DATEDIFF should be fully inclusive. e.g. Is the difference between 9/10 and 9/11 1 day or 2 days? If the latter, you'll want to add 1 to the final product.
declare #d1 datetime, #d2 datetime
select #d1 = '9/9/2011', #d2 = '9/18/2011'
select datediff(dd, #d1, #d2) - (datediff(wk, #d1, #d2) * 2) -
case when datepart(dw, #d1) = 1 then 1 else 0 end +
case when datepart(dw, #d2) = 1 then 1 else 0 end
I found when i used this there was a problem when d1 fell on saturday. Below is what i used to correct this.
declare #d1 datetime, #d2 datetime
select #d1 = '11/19/2011' , #d2 = '11/28/2011'
select datediff(dd, #d1, #d2) +case when datepart(dw, #d1) = 7 then 1 else 0 end - (datediff(wk, #d1, #d2) * 2) -
case when datepart(dw, #d1) = 1 then 1 else 0 end +
case when datepart(dw, #d2) = 1 then 1 else 0 end
BEGIN
DECLARE #totaldays INT;
DECLARE #weekenddays INT;
SET #totaldays = DATEDIFF(DAY, #startDate, #endDate)
SET #weekenddays = ((DATEDIFF(WEEK, #startDate, #endDate) * 2) + -- get the number of weekend days in between
CASE WHEN DATEPART(WEEKDAY, #startDate) = 1 THEN 1 ELSE 0 END + -- if selection was Sunday, won't add to weekends
CASE WHEN DATEPART(WEEKDAY, #endDate) = 6 THEN 1 ELSE 0 END) -- if selection was Saturday, won't add to weekends
Return (#totaldays - #weekenddays)
END
This is on SQL Server 2014
declare #d1 datetime, #d2 datetime
select #d1 = '4/19/2017', #d2 = '5/7/2017'
DECLARE #Counter int = datediff(DAY,#d1 ,#d2 )
DECLARE #C int = 0
DECLARE #SUM int = 0
WHILE #Counter > 0
begin
SET #SUM = #SUM + IIF(DATENAME(dw,
DATEADD(day,#c,#d1))IN('Sunday','Monday','Tuesday','Wednesday','Thursday')
,1,0)
SET #Counter = #Counter - 1
set #c = #c +1
end
select #Sum
If you hate CASE statements as much as I do, and want to be able to use the solution inline in your queries, just get the difference of days and subtract the count of weekend days and you'll have the desired result:
declare #d1 datetime, #d2 datetime, #days int
select #d1 = '2018/10/01', #d2 = '2018/11/01'
SET #days = DateDiff(dd, #d1, #d2) - DateDiff(ww, #d1, #d2)*2
print #days
(The only caveat--or at least point to keep in mind--is that this calculation is not inclusive of the last date, so you might need to add one day to the end date to achieve an inclusive result)
I just want to share the code I created that might help you.
DECLARE #MyCounter int = 0, #TempDate datetime, #EndDate datetime;
SET #TempDate = DATEADD(d,1,'2017-5-27')
SET #EndDate = '2017-6-3'
WHILE #TempDate <= #EndDate
BEGIN
IF DATENAME(DW,#TempDate) = 'Sunday' OR DATENAME(DW,#TempDate) = 'Saturday'
SET #MyCounter = #MyCounter
ELSE IF #TempDate not in ('2017-1-1', '2017-1-16', '2017-2-20', '2017-5-29', '2017-7-4', '2017-9-4', '2017-10-9', '2017-11-11', '2017-12-25')
SET #MyCounter = #MyCounter + 1
SET #TempDate = DATEADD(d,1,#TempDate)
CONTINUE
END
PRINT #MyCounter
PRINT #TempDate
If you do have a holiday table, you can also use that so that you don't have to list all the holidays in the ELSE IF section of the code. You can also create a function for this code and use the function whenever you need it in your query.
I hope this might help too.
Using https://stackoverflow.com/a/1804095 and JeffFisher30's answer above (https://stackoverflow.com/a/14572370/6147425) and my own need to have fractional days, I wrote this:
DateDiff(second,Start_Time,End_Time)/86400.0
-2*DateDiff(week, Start_Time, End_Time)
-Case When (DatePart(weekday, Start_Time)+##DateFirst)%7 = 1 Then 1 Else 0 End
+Case When (DatePart(weekday, End_Time)+##DateFirst)%7 = 1 Then 1 Else 0 End
Use this function to calculate the number of business days excluding Saturday and Sunday. Also it will exclude start date and it will include end date.
-- Select [dbo].[GetBussinessDays] ('02/18/2021', '03/06/2021') -- 11 days
CREATE or ALTER FUNCTION [dbo].[GetBussinessDays] (
#StartDate DATETIME,
#EndDate DATETIME
)
returns INT AS
BEGIN
DECLARE #tempStartDate DATETIME= #StartDate;
DECLARE #tempEndDate DATETIME = #EndDate;
IF(#tempStartDate IS NULL
OR
#tempEndDate IS NULL)
BEGIN
RETURN NULL;
END
--To avoid negative values reverse the date if StartDate is grater than EndDate
IF(#StartDate > #EndDate)
BEGIN
SET #StartDate = #tempEndDate;
SET #EndDate = #tempStartDate;
END
DECLARE #Counter INT = Datediff(day,#StartDate ,#EndDate);
DECLARE #TempCounter INT = 0;
DECLARE #TotalBusinessDays INT = 0;
WHILE #Counter >= 0
BEGIN
IF(#TempCounter > 0 OR #Counter = 1) -- To ignore first day's calculation
Begin
SET #TotalBusinessDays = #TotalBusinessDays + Iif(Datename(dw, Dateadd(day,#TempCounter,#StartDate)) IN('Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday'),1,0)
END
SET #Counter = #Counter - 1
SET #TempCounter = #TempCounter +1
END
RETURN #TotalBusinessDays;
END
Using #Derek Kromm answer (Current Marked Answer)
I have modified so it IS tolerant of any localisations that may be on the target server.
DECLARE #d1 DATETIME, #d2 DATETIME
SELECT #d1 = '10/01/2022', #d2 = '10/28/2022'
SELECT (datediff(dd, #d1, #EndQuery)+1) - (datediff(wk, #d1, dateadd(dd,1,#d2)) * 2)
- CASE WHEN DateName(WEEKDAY, #d1) = 'Sunday' THEN 1 ELSE 0 END -- This includes for start date edge case
+ CASE WHEN DateName(WEEKDAY, #d2) = 'Saturday' THEN 1 ELSE 0 END -- This includes for end date edge case.
This is with the end date being innclusive.
/*
EXAMPLE:
/MONDAY/
SET DATEFIRST 1
SELECT dbo.FUNC_GETDATEDIFFERENCE_WO_WEEKEND('2019-02-01','2019-02-12')
*/
CREATE FUNCTION FUNC_GETDATEDIFFERENCE_WO_WEEKEND
(
#pdtmaLastLoanPayDate DATETIME,
#pdtmaDisbursedDate DATETIME
)
RETURNS BIGINT
BEGIN
DECLARE
#mintDaysDifference BIGINT
SET #mintDaysDifference = 0
WHILE CONVERT(NCHAR(10),#pdtmaLastLoanPayDate,121) <= CONVERT(NCHAR(10),#pdtmaDisbursedDate,121)
BEGIN
IF DATEPART(WEEKDAY,#pdtmaLastLoanPayDate) NOT IN (6,7)
BEGIN
SET #mintDaysDifference = #mintDaysDifference + 1
END
SET #pdtmaLastLoanPayDate = DATEADD(DAY,1,#pdtmaLastLoanPayDate)
END
RETURN ISNULL(#mintDaysDifference,0)
END