The following procedure calculates annual leaves of employees based on the provided empid. First Question: How can I create/modify this procedure to calculate annual leaves for all employees. Second Question: Return more columns like empname, designation, annual leave balance? please note that i am using sql server 2016 community edition.
ALTER proc [dbo].[spAvailalbeAL](#empID int)
as
begin
declare #StartDate datetime
declare #totMonths int
declare #aAnnualLeaves int
declare #avlAL int
set #avlAL = (select sum(Availed) from LeaveDetails where empid = #empID AND TypeID=3)
if ( #avlAL IS NULL)
begin
set #StartDate = '2017-07-01'
set #totMonths = (SELECT DATEDIFF(mm, #StartDate, GETDATE()))
set #aAnnualLeaves = 2
set #aAnnualLeaves = (#aAnnualLeaves*#totMonths)
select #aAnnualLeaves
end
else
begin
set #StartDate = '2017-07-01'
set #totMonths = (SELECT DATEDIFF(mm, #StartDate, GETDATE()))
set #aAnnualLeaves = 2
set #aAnnualLeaves = (#aAnnualLeaves*#totMonths)-#avlAL
select #aAnnualLeaves
end
end
For showing all employees you can pass 0 or Null for #empid parameter and then you can create Temporary Table like
CREATE TABLE #LeaveDetails(EmpID INT,TotalALAvailed INT)
then fill the table
INSERT INTO #LeaveDetails(EmpID,TotalALAvailed) SELECT EmpID,SUM(Availed) FROM LeaveDetails WHERE (EmpID=#EmpID OR #EmpID=0) AND Type=3 GROUP BY EmpID
You can select all required columns in last Select statement.
You need something like this:
Create proc [dbo].[spAvailalbeAL]
as
begin
declare #StartDate datetime = '2017-07-01'
declare #totMonths int
declare #aAnnualLeaves int
set #totMonths = (SELECT DATEDIFF(mm, #StartDate, GETDATE()))
print #totMonths
set #aAnnualLeaves = 2
set #aAnnualLeaves = (#aAnnualLeaves*#totMonths)
print #aAnnualLeaves
SELECT distinct e.EMPLOYEE_NAME,e.desg_cd,sum(isnull(ea.Availed,0)) over ( partition by e.EmpID ),#aAnnualLeaves - sum(isnull(ea.Availed,0)) over ( partition by e.EmpID ) as leaves
from Employee e
inner join LeaveDetails ea
on e.EMPLOYEE_CD = ea.EMPLOYEE_CD
where DATE > #StartDate
AND ea.TypeID=3
end
-- exec spAvailalbeAL
I have this function, which should bring me the end of month date of an invoice.
E.g. Invoice (ARID) have a created date 2015-09-1, the eom is 2015-09-30.
ALTER FUNCTION [dbo].[sfEOM](#ARID int, #Switch int)
RETURNS date
AS
BEGIN
declare #Letzter date
declare #MaxLeistungsdatum as date
if #Switch=1
set #Letzter = (select CONVERT(date, DATEADD(MONTH,DATEDIFF (MONTH,0,tblleistungen.LeistungsDatum),30),0) from dbo.tblleistungen where ARID=#ARID group by ARID,CONVERT(date, DATEADD(MONTH,DATEDIFF(MONTH,0,tblleistungen.LeistungsDatum),30),0) )
else
set #MaxLeistungsdatum=(select max(LeistungsDatum) from tblDatensaetzeBA where ARID=#ARID group by ARID)
set #Letzter = (select CONVERT(date, DATEADD(MONTH,DATEDIFF(MONTH,0,#MaxLeistungsdatum),30),0))
RETURN #Letzter
END
go
To use one function for two different tables I use as #Switch
but
select dbo.sfEOM(9307396,1)
or
select dbo.sfEOM(9307396,2)
brings NULL as result where as
select CONVERT(date, DATEADD(MONTH,DATEDIFF (MONTH,0,tblleistungen.LeistungsDatum),30),0) from dbo.tblleistungen where ARID9307396 group by ARID,CONVERT(date, DATEADD(MONTH,DATEDIFF(MONTH,0,tblleistungen.LeistungsDatum),30),0)
brings the correct date.
When I omit if #Switch=1 and have only
set #Letzter = (select CONVERT(date, DATEADD(MONTH,DATEDIFF (MONTH,0,tblleistungen.LeistungsDatum),30),0) from dbo.tblleistungen where ARID=#ARID group by ARID,CONVERT(date, DATEADD(MONTH,DATEDIFF(MONTH,0,tblleistungen.LeistungsDatum),30),0) )
it works too.
Whats wrong there?
Thanks!
Michael
You need to define the code blocks for the if statement:
ALTER FUNCTION [dbo].[sfEOM](#ARID int, #Switch int)
RETURNS date
AS
BEGIN
declare #Letzter date
declare #MaxLeistungsdatum as date
if #Switch = 1
begin
set #Letzter = (select CONVERT(date, DATEADD(MONTH,DATEDIFF (MONTH,0,tblleistungen.LeistungsDatum),30),0) from dbo.tblleistungen where ARID=#ARID group by ARID,CONVERT(date, DATEADD(MONTH,DATEDIFF(MONTH,0,tblleistungen.LeistungsDatum),30),0) )
end
else
begin
set #MaxLeistungsdatum=(select max(LeistungsDatum) from tblDatensaetzeBA where ARID=#ARID group by ARID)
set #Letzter = (select CONVERT(date, DATEADD(MONTH,DATEDIFF(MONTH,0,#MaxLeistungsdatum),30),0))
end
return #Letzter
end;
go
declare #StartDate varchar(30), #myStartDate date, #iterate int, #DaysDiff int, #NoOfDays varchar (200) , #username varchar(30), #StaffID int
select #DaysDiff = 6, #iterate =0, #StartDate = '2015-04-29', #username = 'itdsnm'
select #StaffID = StaffID from Staff where LoginName = #username
select #myStartDate = cast(#StartDate as DATE)
begin
Create Table #Temp8(Dates date,MyDay int)
While #iterate < #DaysDiff +1
Begin
Insert Into #Temp8(Dates,MyDay)
Select #myStartDate,DATEPART(dw,#myStartDate)
Select #myStartDate = dateadd(dd,1,#myStartDate)
IF (Select COUNT(*) from #Temp8 where Dates In(Select StartDate From Holidays Where Username = #StaffID )) >0
Begin
Select #NoOfDays = 'One of your days fall between a holiday already taken, please review'
Return
End
Else
Select #iterate = #iterate + 1
End
;With Temp2(Dates,MyDay)
As
(Select Dates,MyDay from #Temp8 Where MyDay not in (1,7))
Select #NoOfDays = COUNT(*) from Temp2 Where Dates Not In (Select Date From BankHolidays)
end
Everything works fine in the above procedure, but when it comes to the With statement, it throws me an error "Conversion failed when converting date and/or time from character string." Can Some one help me with this. Thanks in advance
I agree with Tanner that the schema is required to be able to assess the issue (i.e. the column datatypes).
At first glance, though it appears to me that perhaps [Date] in [BankHolidays] is some sort of string datatype and that column contains certain string values that cannot be converted to a DATE type.
I want to have a function within the SQL query which will bring out the current week in SSRS 2005 using parameters. I have declared two variables #FromDate and #ToDate. I am using these two variables in the where clause below
where SH.[] between CONVERT(datetime, #FromDate, 105) and CONVERT(datetime, #ToDate, 105)
How do I bring out the current week using #FromDat and #ToDate? Can I have any help?
Thankss
CREATE TABLE dbo.TestDates (
SaleID TINYINT IDENTITY(1,1),
Amount NUMERIC(9,2),
SaleDate DATETIME
);
GO
INSERT INTO dbo.TestDates (Amount, SaleDate)
VALUES (200.00, '2014-12-15'),
(130.00, '2014-12-16'),
(40.00, '2014-12-17'),
(70.00, '2014-12-18'),
(590.00, '2014-12-19')
-----------------------------------------
CREATE FUNCTION dbo.uspGetCurrentWeek(#From VARCHAR(100)
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE #StartCounter TINYINT = 1
DECLARE #EndCounter TINYINT = 5
WHILE #StartCounter <= #EndCounter
BEGIN
DECLARE #String VARCHAR(100) = ( SELECT 'Week' +
CAST(DATEPART(WEEK, SaleDate) AS VARCHAR(2))
FROM dbo.TestDates
WHERE SaleDate = #From )
SET #StartCounter = #StartCounter +1
END
RETURN #String
END
--------------
-----Test data ----
SELECT *, dbo.uspGetCurrentWeek('2014-12-15')
FROM dbo.TestDates;
---------------------------------
This is more of a syntax question
I'm trying to write a store procedure or function that I can embed into a query such as:
select * from MyBigProcOrFunction
I'm trying to define a tabular function but I do not understand how to do it as I build tmp tables to work out the data before I finally have the return at the endtable. My mark up for my code is:
create function FnGetCompanyIdWithCategories()
returns table
as
return
(
select * into a #tempTable from stuff
'
etc
'
select companyid,Company_MarketSector from #tempTables 'the returning table data
)
If I define a function, How do I return it as a table?
You can't access Temporary Tables from within a SQL Function. You will need to use table variables so essentially:
ALTER FUNCTION FnGetCompanyIdWithCategories()
RETURNS #rtnTable TABLE
(
-- columns returned by the function
ID UNIQUEIDENTIFIER NOT NULL,
Name nvarchar(255) NOT NULL
)
AS
BEGIN
DECLARE #TempTable table (id uniqueidentifier, name nvarchar(255)....)
insert into #myTable
select from your stuff
--This select returns data
insert into #rtnTable
SELECT ID, name FROM #mytable
return
END
Edit
Based on comments to this question here is my recommendation. You want to join the results of either a procedure or table-valued function in another query. I will show you how you can do it then you pick the one you prefer. I am going to be using sample code from one of my schemas, but you should be able to adapt it. Both are viable solutions first with a stored procedure.
declare #table as table (id int, name nvarchar(50),templateid int,account nvarchar(50))
insert into #table
execute industry_getall
select *
from #table
inner join [user]
on account=[user].loginname
In this case, you have to declare a temporary table or table variable to store the results of the procedure. Now Let's look at how you would do this if you were using a UDF
select *
from fn_Industry_GetAll()
inner join [user]
on account=[user].loginname
As you can see the UDF is a lot more concise easier to read, and probably performs a little bit better since you're not using the secondary temporary table (performance is a complete guess on my part).
If you're going to be reusing your function/procedure in lots of other places, I think the UDF is your best choice. The only catch is you will have to stop using #Temp tables and use table variables. Unless you're indexing your temp table, there should be no issue, and you will be using the tempDb less since table variables are kept in memory.
Use this as a template
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE FUNCTION <Table_Function_Name, sysname, FunctionName>
(
-- Add the parameters for the function here
<#param1, sysname, #p1> <data_type_for_param1, , int>,
<#param2, sysname, #p2> <data_type_for_param2, , char>
)
RETURNS
<#Table_Variable_Name, sysname, #Table_Var> TABLE
(
-- Add the column definitions for the TABLE variable here
<Column_1, sysname, c1> <Data_Type_For_Column1, , int>,
<Column_2, sysname, c2> <Data_Type_For_Column2, , int>
)
AS
BEGIN
-- Fill the table variable with the rows for your result set
RETURN
END
GO
That will define your function. Then you would just use it as any other table:
Select * from MyFunction(Param1, Param2, etc.)
You need a special type of function known as a table valued function. Below is a somewhat long-winded example that builds a date dimension for a data warehouse. Note the returns clause that defines a table structure. You can insert anything into the table variable (#DateHierarchy in this case) that you want, including building a temporary table and copying the contents into it.
if object_id ('ods.uf_DateHierarchy') is not null
drop function ods.uf_DateHierarchy
go
create function ods.uf_DateHierarchy (
#DateFrom datetime
,#DateTo datetime
) returns #DateHierarchy table (
DateKey datetime
,DisplayDate varchar (20)
,SemanticDate datetime
,MonthKey int
,DisplayMonth varchar (10)
,FirstDayOfMonth datetime
,QuarterKey int
,DisplayQuarter varchar (10)
,FirstDayOfQuarter datetime
,YearKey int
,DisplayYear varchar (10)
,FirstDayOfYear datetime
) as begin
declare #year int
,#quarter int
,#month int
,#day int
,#m1ofqtr int
,#DisplayDate varchar (20)
,#DisplayQuarter varchar (10)
,#DisplayMonth varchar (10)
,#DisplayYear varchar (10)
,#today datetime
,#MonthKey int
,#QuarterKey int
,#YearKey int
,#SemanticDate datetime
,#FirstOfMonth datetime
,#FirstOfQuarter datetime
,#FirstOfYear datetime
,#MStr varchar (2)
,#QStr varchar (2)
,#Ystr varchar (4)
,#DStr varchar (2)
,#DateStr varchar (10)
-- === Previous ===================================================
-- Special placeholder date of 1/1/1800 used to denote 'previous'
-- so that naive date calculations sort and compare in a sensible
-- order.
--
insert #DateHierarchy (
DateKey
,DisplayDate
,SemanticDate
,MonthKey
,DisplayMonth
,FirstDayOfMonth
,QuarterKey
,DisplayQuarter
,FirstDayOfQuarter
,YearKey
,DisplayYear
,FirstDayOfYear
) values (
'1800-01-01'
,'Previous'
,'1800-01-01'
,180001
,'Prev'
,'1800-01-01'
,18001
,'Prev'
,'1800-01-01'
,1800
,'Prev'
,'1800-01-01'
)
-- === Calendar Dates =============================================
-- These are generated from the date range specified in the input
-- parameters.
--
set #today = #Datefrom
while #today <= #DateTo begin
set #year = datepart (yyyy, #today)
set #month = datepart (mm, #today)
set #day = datepart (dd, #today)
set #quarter = case when #month in (1,2,3) then 1
when #month in (4,5,6) then 2
when #month in (7,8,9) then 3
when #month in (10,11,12) then 4
end
set #m1ofqtr = #quarter * 3 - 2
set #DisplayDate = left (convert (varchar, #today, 113), 11)
set #SemanticDate = #today
set #MonthKey = #year * 100 + #month
set #DisplayMonth = substring (convert (varchar, #today, 113), 4, 8)
set #Mstr = right ('0' + convert (varchar, #month), 2)
set #Dstr = right ('0' + convert (varchar, #day), 2)
set #Ystr = convert (varchar, #year)
set #DateStr = #Ystr + '-' + #Mstr + '-01'
set #FirstOfMonth = convert (datetime, #DateStr, 120)
set #QuarterKey = #year * 10 + #quarter
set #DisplayQuarter = 'Q' + convert (varchar, #quarter) + ' ' +
convert (varchar, #year)
set #QStr = right ('0' + convert (varchar, #m1ofqtr), 2)
set #DateStr = #Ystr + '-' + #Qstr + '-01'
set #FirstOfQuarter = convert (datetime, #DateStr, 120)
set #YearKey = #year
set #DisplayYear = convert (varchar, #year)
set #DateStr = #Ystr + '-01-01'
set #FirstOfYear = convert (datetime, #DateStr)
insert #DateHierarchy (
DateKey
,DisplayDate
,SemanticDate
,MonthKey
,DisplayMonth
,FirstDayOfMonth
,QuarterKey
,DisplayQuarter
,FirstDayOfQuarter
,YearKey
,DisplayYear
,FirstDayOfYear
) values (
#today
,#DisplayDate
,#SemanticDate
,#Monthkey
,#DisplayMonth
,#FirstOfMonth
,#QuarterKey
,#DisplayQuarter
,#FirstOfQuarter
,#YearKey
,#DisplayYear
,#FirstOfYear
)
set #today = dateadd (dd, 1, #today)
end
-- === Specials ===================================================
-- 'Ongoing', 'Error' and 'Not Recorded' set two years apart to
-- avoid accidental collisions on 'Next Year' calculations.
--
insert #DateHierarchy (
DateKey
,DisplayDate
,SemanticDate
,MonthKey
,DisplayMonth
,FirstDayOfMonth
,QuarterKey
,DisplayQuarter
,FirstDayOfQuarter
,YearKey
,DisplayYear
,FirstDayOfYear
) values (
'9000-01-01'
,'Ongoing'
,'9000-01-01'
,900001
,'Ong.'
,'9000-01-01'
,90001
,'Ong.'
,'9000-01-01'
,9000
,'Ong.'
,'9000-01-01'
)
insert #DateHierarchy (
DateKey
,DisplayDate
,SemanticDate
,MonthKey
,DisplayMonth
,FirstDayOfMonth
,QuarterKey
,DisplayQuarter
,FirstDayOfQuarter
,YearKey
,DisplayYear
,FirstDayOfYear
) values (
'9100-01-01'
,'Error'
,null
,910001
,'Error'
,null
,91001
,'Error'
,null
,9100
,'Err'
,null
)
insert #DateHierarchy (
DateKey
,DisplayDate
,SemanticDate
,MonthKey
,DisplayMonth
,FirstDayOfMonth
,QuarterKey
,DisplayQuarter
,FirstDayOfQuarter
,YearKey
,DisplayYear
,FirstDayOfYear
) values (
'9200-01-01'
,'Not Recorded'
,null
,920001
,'N/R'
,null
,92001
,'N/R'
,null
,9200
,'N/R'
,null
)
return
end
go
You don't need (shouldn't use) a function as far as I can tell. The stored procedure will return tabular data from any SELECT statements you include that return tabular data.
A stored proc does not use RETURN statements.
CREATE PROCEDURE name
AS
SELECT stuff INTO #temptbl1
.......
SELECT columns FROM #temptbln