Here's my sample (SQL Server 2012):
DECLARE @Salary DECIMAL(18, 2), @FromDate DATE, @ToDate DATE;
SET @Salary = 10000;
SET @FromDate = '2014-04-22';
SET @ToDate = '2014-05-08';
WITH [Salary] ( [Date], [WorkingDays], [TotalDays])
AS ( (SELECT DATEADD(dd, 1, EOMONTH(@FromDate, -1)) AS [Date],
( CASE
WHEN (@ToDate <= EOMONTH (@FromDate)) THEN (DATEDIFF(dd, @FromDate, @ToDate))
ELSE (DATEDIFF(dd, @FromDate, EOMONTH(@FromDate)) + 1)
END ) AS [WorkingDays],
DAY(EOMONTH(@FromDate)) AS [TotalDays] )
UNION ALL
(SELECT DATEADD(mm, 1, [Date]) AS [Date],
( CASE
WHEN (@ToDate <= EOMONTH (DATEADD(mm, 1, [Date]))) THEN (DATEDIFF(dd, (DATEADD(mm, 1, [Date])), @ToDate))
ELSE (DATEDIFF(dd, (DATEADD(mm, 1, [Date])), EOMONTH(DATEADD(mm, 1, [Date]))) + 1)
END ) AS [WorkingDays],
DAY(EOMONTH([Date], 1)) AS [TotalDays]
FROM [Salary]
WHERE (MONTH([Date]) < MONTH(@ToDate)) OR (YEAR([Date]) < YEAR(@ToDate))) )
SELECT CONVERT(DECIMAL(18, 2), ( SUM(@Salary * [WorkingDays] / [TotalDays]) )) AS [Salary]
FROM [Salary]
OPTION (MAXRECURSION 32747);
This is important: If you're using a previous version of
SQL Server (2005, 2008, 2008 R2), you need to change the
EOMONTH function with other functions or create a user defined function, which returns the last day of the month. Also, you can optimize this by creating a function, which returns the first day of the month as well.
So how this works? First of all, I am getting working days and total days for each month:
Month WorkingDays TotalDays
April 9 30
May 7 31
Note:
@ToDate
is not included! Then I am calculating the sum of salary using this formula: Salary = @Salary * [WorkingDays] / [TotalDays]. The result is
5258.06 or ((10000 * 9 / 30) + (10000 * 7 / 31)).
If
@FromDate = '2014-04-01'
and
@ToDate = '2015-07-30'
, then the result is
159354.84. The last day (2015-07-30) is not included. If that day would be included, the result would be
160000.00 (16 months).