SQL server 2008 R2 Scalar function does not work - sql-server

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

Related

Get data from the last day of the month without the use of loops or variables

I wrote a query that should select the last record of each month in a year. I'd like to create a View based on this select, that I could run later in my project, but unfortunately I can't use any while loops or variables in a view command. Is there a way to select all these records - last days of a month in a View that I can use later?
My desired effect of the view:
The query that I'm trying to implement in a view:
DECLARE #var_day01 DATETIME;
DECLARE #month int;
SET #month = 1;
DROP TABLE IF EXISTS #TempTable2;
CREATE TABLE #TempTable2 (ID int, date datetime, INP2D float, INP3D float, ID_device varchar(max));
WHILE #month < 13
BEGIN
SELECT #var_day01 = CONVERT(nvarchar, date) FROM (SELECT TOP 1 * FROM data
WHERE DATEPART(MINUTE, CONVERT(nvarchar, date)) = '59'
AND
MONTH(CONVERT(nvarchar, date)) = (CONVERT(nvarchar, #month))
ORDER BY date DESC
) results
ORDER BY date DESC;
INSERT INTO #TempTable2 (ID, date, INP2D,INP3D,ID_device)
SELECT * FROM data
WHERE DATEPART(MINUTE, CONVERT(nvarchar, date)) = '59'
AND
MONTH(CONVERT(nvarchar, date)) = (CONVERT(nvarchar, #month))
AND
DAY(CONVERT(nvarchar, date)) = CONVERT(datetime, DATEPART(DAY, #var_day01))
ORDER BY date DESC
PRINT #var_day01
SET #month = #month +1;
END
SELECT * FROM #TempTable2;
If you are actually just after the single most recent row for each month, there is no need for a while loop to achieve this. You just need to identify the max date value for each month and then filter your source data for those for those rows.
One way to achieve this is via a row_number window function:
declare #t table(id int,dt datetime2);
insert into #t values(1,getdate()-40),(2,getdate()-35),(3,getdate()-25),(4,getdate()-10),(5,getdate());
select id
,id_device
,dt
from(select id
,id_device
,dt
,row_number() over (partition by id_device, year(dt), month(dt) order by dt desc) as rn
from #t
) as d
where rn = 1;
You can add a simple where to your select statement, in where clause you will add one day to the date field and then select the day from the resultant date. If the result date is 1 then only you will select that record
the where clause for your query will be : Where Day(DATEADD(d,1,[date])) = 1

Creating a monthly report in T-SQL

I have a table with the following columns
CaseID
DateLogged
CompletionDate
I am trying to create a monthly stock report.
I need to identify monthly which cases are New, current and Completed each month
for instance, All cases logged only in August are new cases while all cases completed in august would show completed and all cases logged that are not completed will be current.
DROP TABLE IF EXISTS #temptable
-- Create date variables
SET dateformat ymd
DECLARE #datefrom datetime = CONVERT(DATETIME, '2019-04-01 00:00:00', 121)
DECLARE #dateto datetime = (SELECT CAST(DATEADD(DAY, -DAY(GETDATE()), GETDATE()) AS date))
-- Recursive date table creation
;WITH monthserial AS
(
SELECT #datefrom AS monthdate
UNION ALL
SELET DATEADD(MONTH, 1, monthdate)
FROM monthserial
WHERE monthdate < #dateto
)
SELECT MN.*
INTO #temptable
FROM monthserial MN
SELECT * FROM MainTable VW
CROSS JOIN #temptable TBL
WHERE DateLogged <= monthdate) test
You will need to use case-when for your situation:
select CaseID,
case
when not (CompletionDate is null) then 'Completed'
when DateLogged >= #input then 'New'
else 'Current'
end
from yourtable
order by DateLogged;
EDIT
Since we are interested about the last entry, we can add a where clause, like this:
select CaseID,
case
when not (CompletionDate is null) then 'Completed'
when DateLogged >= #input then 'New'
else 'Current'
end
from yourtable
where not exists (
select 1
from yourtable inner
where inner.CaseID = yourtable.CaseID and inner.CompletionDate < yourtable.CompletionDate
)
order by DateLogged;

Calculate Annual Leaves for All employees and return more than one column in SQL Server

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

Get number of weekends between two dates in SQL

I need to get the number of weekends between dates in sql as a function. I have tried but stuck up somewhere in the logic.
CREATE FUNCTION fnc_NumberOfWeekEnds(#dFrom DATETIME, #dTo DATETIME)
RETURNS INT AS
BEGIN
Declare #weekends int
Set #weekends = 0
While #dFrom <= #dTo Begin
If ((datepart(dw, #dFrom) = 1))
Set #weekends = #weekends + 1
Set #dFrom = DateAdd(d, 1, #dFrom)
End
Return (#weekends)
END
I tried out this logic with several edge cases and it seems to work.
SELECT DATEDIFF(d, #dFrom, #dTo)/7+1
+ CASE WHEN DATEPART(dw,#dFrom) IN (1,7) THEN -1 ELSE 0 END
+ CASE WHEN DATEPART(dw,#dTo) IN (1,7) THEN -1 ELSE 0 END
You can change the CASE statements depending on how you want to handle cases where the start or end date is in a weekend. In my case I'm not including the weekend if the start or end date is a Saturday or Sunday.
Try replacing the if statement with this:
If ((datepart(dw, #dFrom) = 1) OR (datepart(dw, #dFrom) = 7))
You should also check the end of the week to get the result.
DECLARE #date_from DATETIME,
#date_to DATETIME
/*TEMPORARY TABLE*/
DECLARE #DATES AS TABLE (
GDate DATETIME
)
SELECT #date_from ='2019-09-10'
SELECT #date_to ='2019-10-10'
/*DATE GENERATED*/
WITH dates
AS (
SELECT #date_from AS dt
UNION ALL
SELECT DATEADD(D, 1, dt)
FROM dates
WHERE dt < #date_to
)
/*INSERTED DATES INTO TEMP TABLE */
INSERT INTO #DATES
SELECT CONVERT(DATETIME, dt) AS Gdate FROM dates
/*Get Records from temp table*/
SELECT Gdate FROM #DATES
Used below logic to calculate the no of Saturdays or Sundays between a start date and end date.
CREATE FUNCTION dbo.WEEKEND_COUNT
(
#Start_Date datetime,
#End_Date datetime
)
RETURNS int
AS
BEGIN
Declare #count int = 0;
while #Start_Date<=#End_Date
Begin
IF DatePart(WEEKDAY,#Start_Date) = 1 or DatePart(WEEKDAY,#Start_Date) = 7
SET #count=#count+1
SET #Start_Date=DateAdd(d,1,#Start_Date)
END
return #count
END
--Use below to get the count of Saturdays and Sundays
Select dbo.WEEKEND_COUNT('Your start date','your end date')
This will give you the number of sunday between two dates
SELECT DateDiff(ww, #dFrom, #dTo) as NumOfSundays

Query to show result in the charts

I have to implement charts in my application. Suppose i have a table structure
DECLARE #SONGS TABLE
(
[ID] INT IDENTITY,
[SONGNAME] VARCHAR(20),
[CREATEDDATE] DATETIME
)
INSERT INTO #SONGS
SELECT 'SONG1','20091102' UNION ALL
SELECT 'SONG2','20091103' UNION ALL
SELECT 'SONG3','20091107' UNION ALL
SELECT 'SONG4','20091107' UNION ALL
SELECT 'SONG5','20091107' UNION ALL
SELECT 'SONG6','20091109'
Now user will pass start date and end date from outside as parameters like below
DECLARE #STARTDATE DATETIME
DECLARE #ENDDATE DATETIME
SET #STARTDATE='20091101'
SET #ENDDATE='20091111'
Now user has further one more option(SAY #OPTION VARCHAR(20) ) whether he wants the results with dates split into individual dates between the start date and end date, second option he can choose to have the results with dates into the months between the start date and end date, similarly for year.
--OUTPUT I NEED IS when #OPTION IS DATE
DATE [SONGCOUNT]
------------------------------------------
20091101 0
20091102 1
20091103 1
20091104 0
20091105 0
20091106 0
20091107 3
20091108 0
20091109 1
20091110 0
20091111 0
Similarly i want the results with dates splitted according the option(day,week,month,year) having count next to it.
My goal is to display date on xaxis and count on y axis, can you suggest me a way to implement the same.
DECLARE #dimDate TABLE (
myDate datetime
,dt int
,yr int
,ym int
)
DECLARE #dte datetime
SET #dte = #STARTDATE
WHILE #dte <= #ENDDATE
BEGIN
INSERT INTO #dimDate (myDate, dt, yr, ym)
VALUES(
#dte
,datepart(yy,#dte)*10000+ datepart(mm,#dte)*100 + datepart(dd,#dte)
,datepart(yy,#dte)
,datepart(yy,#dte)*100+ datepart(mm,#dte)
)
SET #dte = dateadd(dd,1,#dte)
END
.
DECLARE #option varchar(2)
SET #option ='dt'
.
-- per day
IF #option ='dt'
BEGIN
SELECT d.dt, COUNT(s.ID) AS "song_count"
FROM #dimDate AS d
LEFT JOIN #SONGS AS s ON d.myDate = s.CREATEDDATE
GROUP BY d.dt
END
.
-- per year
IF #option ='yr'
BEGIN
SELECT d.yr, COUNT(s.ID) AS "song_count"
FROM #dimDate AS d
LEFT JOIN #SONGS AS s ON d.myDate = s.CREATEDDATE
GROUP BY d.yr
END
.
-- per year-month
IF #option ='ym'
BEGIN
SELECT d.ym, COUNT(s.ID) AS "song_count"
FROM #dimDate AS d
LEFT JOIN #SONGS AS s ON d.myDate = s.CREATEDDATE
GROUP BY d.ym
END
For making the results in x & y axis, use PIVOT(SQL server 2005+).
This kind of queries are called CROSS TAB QUERIES
For your reference
SQL Server PIVOT examples

Resources