I have the following query which works as is (people will probably cringe, but try to ignore how bad it is):
DECLARE #submit_day DATETIME;
DECLARE #meeting_day DATETIME;
DECLARE #start_time_of_business_day DATETIME;
DECLARE #business_day_hours FLOAT;
DECLARE #submit_time DATETIME;
DECLARE #meeting_time DATETIME;
DECLARE #num1 FLOAT
DECLARE #num2 FLOAT
DECLARE #num3 FLOAT
SET #meeting_day = '2013-06-24'; -- USER GENERATED VARIABLE
SET #meeting_time = '15:45'; -- USER GENERATED
SET #submit_day = CONVERT(VARCHAR(10),GETDATE(),101);
SET #submit_time = CONVERT(VARCHAR(8),GETDATE(),108);
SET #start_time_of_business_day = '09:00';
SET #business_day_hours = 8.5;
SET #num1 = ((DATEDIFF(dd, #submit_day, #meeting_day))
-(DATEDIFF(wk, #submit_day, #meeting_day) * 2)
-(CASE WHEN DATEPART(dw, #submit_day) = 1 THEN 1 ELSE 0 END)
-(CASE WHEN DATEPART(dw, #meeting_day) = 7 THEN 1 ELSE 0 END)
-(SELECT COUNT(*) FROM intranet.dbo.bank_holiday WHERE the_date BETWEEN #submit_day AND #meeting_day)) * #business_day_hours
SET #num2 = (select datediff(minute, #start_time_of_business_day, #submit_time)) / 60.0
SET #num3 = (select datediff(minute, #start_time_of_business_day, #meeting_time)) / 60.0
select #num1 - #num2 + #num3 as [hours]
So I want to set this up as a stored procedure, so I tried the following:
USE [INTRANET]
GO
/****** Object: StoredProcedure [dbo].[BusinessHours] Script Date: 06/21/2013 15:19:47 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[BusinessHours]
#meeting_date DATETIME,
#meeting_time DATETIME
AS
DECLARE #submit_day DATETIME;
DECLARE #submit_time DATETIME;
DECLARE #start_time_of_business_day DATETIME;
DECLARE #business_day_hours FLOAT;
DECLARE #num1 FLOAT
DECLARE #num2 FLOAT
DECLARE #num3 FLOAT
SET #submit_day = CONVERT(VARCHAR(10),GETDATE(),101);
SET #submit_time = CONVERT(VARCHAR(8),GETDATE(),108);
SET #start_time_of_business_day = '09:00';
SET #business_day_hours = 8.5;
SET #num1 = ((DATEDIFF(dd, #submit_day, #meeting_day))
-(DATEDIFF(wk, #submit_day, #meeting_day) * 2)
-(CASE WHEN DATEPART(dw, #submit_day) = 1 THEN 1 ELSE 0 END)
-(CASE WHEN DATEPART(dw, #meeting_day) = 7 THEN 1 ELSE 0 END)
-(SELECT COUNT(*) FROM intranet.dbo.bank_holiday WHERE the_date BETWEEN #submit_day AND #meeting_day)) * #business_day_hours
SET #num2 = (select datediff(minute, #start_time_of_business_day, #submit_time)) / 60.0
SET #num3 = (select datediff(minute, #start_time_of_business_day, #meeting_time)) / 60.0
select #num1 - #num2 + #num3 as [hours]
This gives me an error:
Msg 137, Level 15, State 2, Procedure BusinessHours, Line 25
Must declare the scalar variable "#meeting_day".
Msg 137, Level 15, State 2, Procedure BusinessHours, Line 29
Must declare the scalar variable "#meeting_day".
Tried searching, but can't figure out how to get this to work.
Yes. You renamed your DECLAREd variable #meeting_day to the parameter #meeting_date.
Fix that.
You typed "meeting_date" instead of "meeting_day" in your parameter declaration.
CREATE PROCEDURE [dbo].[BusinessHours]
#meeting_day DATETIME, --ERROR IS HERE
#meeting_time DATETIME
AS
Related
actually the function does not work properly after many tests
for example I've triedSelect * from [dbo].[fn_GetLeaveDays] ('2020-09-24',1,'2020-09-25',1,1,1)
and it should returns only 1 as friday is weekend but it returns 2
could you please assist to find whats wrong in the function
ALTER FUNCTION [dbo].[fn_GetLeaveDays] (#DateFrom datetime2,
#CalendarFunction int,
#DateTo AS datetime2,
#AdjustMode bit,
#AdjustWeekEnds bit,
#AdjustHolidays bit)
RETURNS #tbl table (totaldays int)
AS
BEGIN
IF #DateFrom > #DateTo
BEGIN
DECLARE #T datetime2 = #DateTo,
#F datetime2 = #DateFrom;
SELECT #DateFrom = #T,
#DateTo = #F;
END;
DECLARE #Count AS int = 0,
#Date AS datetime2 = #DateFrom;
WHILE #Date < #DateTo
BEGIN
IF ((DATEPART(WEEKDAY, #Date) IN (6)
AND #AdjustWeekEnds = 1)
OR EXISTS (SELECT *
FROM [C3DCalendar].[dbo].[PRIMAVERA_CALENDAR_HOLIDAYS]
WHERE holiday_date = #Date
AND calendar_key = #CalendarFunction
AND #AdjustHolidays = 1))
BEGIN
SELECT #Count = #Count + 1;
END;
SELECT #Date = DATEADD(DAY, 1, #Date);
END;
INSERT INTO #tbl
SELECT (DATEDIFF(DAY, #DateFrom, #DateTo) - (#Count)) + #AdjustMode;
RETURN;
END;
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;
I tried to execute this procedure but I am getting error.
I tried to execute using:
execute Currentmonth 20141220
Error:
Msg 208, Level 16, State 1, Procedure Currentmonth, Line 15
Invalid object name 'DimDate'
Why I am getting this error? Can you please tell me the errors in the query for creating stored procedure and what are the parameters I am expecting?
create procedure Currentmonth
#Completeddatekey varchar(20)
as
begin
Getting the current date and formatting it
Declare #currentdate varchar(30)
set #currentdate = convert(Varchar(20), getdate()-1, 101)
print #currentdate
Getting DayofMonth and EndofMonth from DimDate
Declare #dayofmonth int
Declare #endofmonth int
select #dayofmonth = DayofMonth, #endofmonth = EndofMonthDateKey
from bi.dbo.DimDate
where datekey = #currentdate
Getting HierMonthEndKey
declare #hiermonthendkey int
select #hiermonthendkey = MAX(HierMonthEndKey)
from DimHospiceHiearchy
where HierMonthEndKey <= #currentdate+1
Declare #day
For Loop
Declare #i int = 0
declare #startdate varchar(20)
select #startdate = CAST(CAST(YEAR(convert(Varchar(20), getdate()-1, 101)) AS VARCHAR(4))
+ '/' + CAST(MONTH(convert(Varchar(20), getdate()-1, 101)) AS VARCHAR(2)) + '/01' AS DATETIME)+1
While #i <=#dayofmonth
begin
set #startdate = #startdate+#i
exec MA010103 #completeddatekey, #hiermonthendkey
set #i = #i+1
end
end
This error occurs when an object that does not exist is referenced. If the object exists, you might need to include the owner's name in the object name.
Please check the table exists in the mentioned database ?
select #dayofmonth = DayofMonth, #endofmonth = EndofMonthDateKey from
bi.dbo.DimDate
where datekey = #currentdate
Instead of
Declare #dayofmonth int
Declare #endofmonth int
select #dayofmonth = DayofMonth, #endofmonth = EndofMonthDateKey from bi.dbo.DimDate
where datekey = #currentdate
Please try
Declare #dayofmonth int
Declare #endofmonth int
select #dayofmonth = DayofMonth, #endofmonth = EndofMonthDateKey from DimDate
where datekey = #currentdate
Or check if DimDate Table exists
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.
In my table I have a Month(tinyint) and a Day(tinyint) field. I would like to have a function that takes this month and day and produces a datetime for the next date(including year) given this month and day.
So if I had Month = 9, Day = 7 it would produce 9/7/2009.
If I had Month 1, Day 1 it would produce 1/1/2010.
something like this would work. It's variation on your method, but it doesn't use the MM/DD/YYYY literal format, and it won't blowup against bad input (for better or for worse).
declare #month tinyint
declare #day tinyint
set #month = 9
set #day = 1
declare #date datetime
-- this could be inlined if desired
set #date = convert(char(4),year(getdate()))+'0101'
set #date = dateadd(month,#month-1,#date)
set #date = dateadd(day,#day-1,#date)
if #date <= getdate()-1
set #date = dateadd(year,1,#date)
select #date
Alternatively, to create a string in YYYYMMDD format:
set #date =
right('0000'+convert(char(4),year(getdate())),4)
+ right('00'+convert(char(2),#month),2)
+ right('00'+convert(char(2),#day),2)
Another method, which avoids literals all together:
declare #month tinyint
declare #day tinyint
set #month = 6
set #day = 24
declare #date datetime
declare #today datetime
-- get todays date, stripping out the hours and minutes
-- and save the value for later
set #date = floor(convert(float,getdate()))
set #today = #date
-- add the appropriate number of months and days
set #date = dateadd(month,#month-month(#date),#date)
set #date = dateadd(day,#day-day(#date),#date)
-- increment year by 1 if necessary
if #date < #today set #date = dateadd(year,1,#date)
select #date
Here is my sql example so far. I don't really like it though...
DECLARE #month tinyint,
#day tinyint,
#date datetime
SET #month = 1
SET #day = 1
-- SET DATE TO DATE WITH CURRENT YEAR
SET #date = CONVERT(datetime, CONVERT(varchar,#month) + '/' + CONVERT(varchar,#day) + '/' + CONVERT(varchar,YEAR(GETDATE())))
-- IF DATE IS BEFORE TODAY, ADD ANOTHER YEAR
IF (DATEDIFF(DAY, GETDATE(), #date) < 0)
BEGIN
SET #date = DATEADD(YEAR, 1, #date)
END
SELECT #date
Here's a solution with PostgreSQL
your_date_calculated = Year * 10000 + Month * 100 + Day
gives you a date like 20090623.
select cast( cast( your_date_calculated as varchar ) as date ) + 1
Here's my version. The core of it is just two lines, using the DATEADD function, and it doesn't require any conversion to/from strings, floats or anything else:
DECLARE #Month TINYINT
DECLARE #Day TINYINT
SET #Month = 9
SET #Day = 7
DECLARE #Result DATETIME
SET #Result =
DATEADD(month, ((YEAR(GETDATE()) - 1900) * 12) + #Month - 1, #Day - 1)
IF (#Result < GETDATE())
SET #Result = DATEADD(year, 1, #Result)
SELECT #Result