Payroll computation - sql-server

I need you to help me. I have to do a program that calculates the payroll in Management Sql Server 2014. The program should be something like that:
The salary is the sum of gross salary and paid holidays: Sal = Gross_ Salary + Paid_Holiday
For the computation of the Paid_ Holiday we need:
The salary from the previous 6 months:
Sal_6 + Sal_5 + Sal_4 + Sal_3 + Sal_2 + Sal_1 = Base
With Sal_6 = GrossSal_6 + Paid_Holiday_6 ( as i said above)
...
The number of days worked or holiday days from the previous 6 months:
NOdays_6 + NOdays_5 + NOdays_4 + NOdays_3 + NOdays_2 + NOdays_1 = SumOfDays
The paid holiday is: Paid_Holiday= BASE/SumOfDays * NOdays.
From the database I have the following tables:
Entry ( Identry, Gross_Salary, NOdayworked, Date, IDEmplyee )
Employee (IDEmplyee, Name, DateofEmployment)
Holiday ( IDHoliday, StartDate, FinalDate, IDEmployee)
The employee has an seniority certificate with the last 6 salaries from the previous employer.
Certificate ( IdCertificate, date, Gross_Salary, NOdayworked, Paid_Holiday, NOdays, IDEmployee)
Because I need the last paid holidays and salary to form the gross salary I thought that I should used a temporary table. This table will retain the data from the certificate and the data from Entry
What I have tried so far is the following stored procedure:
create proc payroll
#idemployee int
as
create table #tmp( id int identity(1,1) primary key, date1 date, grosssalary money, idemployee int, nodaysworked int, paidholiday money, noofdays int)
insert into #tmp ( date1 , grosssalary , idemployee , nodaysworked , paidholiday , noofdays )
Select Top 6 Date,
Gross_Salary,
IDEmployee,
NOdayworked,
Paid_Holiday,
IDEmployee
from Certificate
WHERE IDEmployee = #idemployee
ORDER BY Date asc
And after that I have to take for every paidholiday the last 6 Salary
Paid_Holiday= BASE/SumOfDays * NOdays but I don't know exactly how I should do. I thought about a cursor or something.
PS: If you didn't understand please let me know. My mother tongue is not English ( also this program is not available for all the countries.
The program is valid in Romania)

Related

How to generate AutoIncrement number with prefix of financial year?

My Client wants to generate a code for every ticket number that goes into database based on the financial year they are working (April current year to March next year) and number needs to reset to 0 where the financial year changes
Example:
ID
17/18/0000001
17/18/0000002
...
18/19/0000001
18/19/0000002
...
If the financial year is stored in database like starting an ending month and year. How we can check that this is the next year broda! reset the numbers.
I wouldn't attempt to try and maintain such a counter internally. Rather, I would generate at the time of querying. The query below assumes that your table does have a single ordinary auto increment counter ID as well as a year int column for the fiscal year. We can use the following to generate the counter you want:
SELECT
RIGHT(CONVERT(varchar(4), year), 2) + '/' +
RIGHT(CONVERT(varchar(4), year + 1), 2) + '/' +
RIGHT('0000000' +
CAST(ROW_NUMBER() OVER (PARTITION BY year ORDER BY ID) AS VARCHAR), 7)
FROM yourTable;
Demo
Client is always right. Suppose you have a table
create table #trans(
id int identity(1,1),
transDate datetime
--other fields
)
--the table is filled
declare #dStart date='20160401', --start and end dates
#dEnd date='20170331' --of the first financial year
;with fy as ( -- fill following years
select 1 id, #dStart dStart, #dEnd dEnd
union all
select id+1,DATEADD(year,1,dStart),DATEADD(year,1,dEnd)
from fy
where id<5 --"majic" 5 is arbitrary
)
select dStart,dEnd,t.*,
right(cast(year(dstart) as varchar),2)+'/'+right(cast(year(dEnd) as varchar),2)+'/' -- F.Y. label
+ FORMAT( ROW_NUMBER() over(
partition by right(cast(year(dstart) as varchar),2)+'/'+right(cast(year(dEnd) as varchar),2)+'/' --restart numbering each F.Y.
order by t.id),'000000') ticket
from fy
inner join #trans t on cast(t.transDate as date) between fy.dStart and fy.dEnd
And have what the Client wants.
Disclaimer: If some data are deleted then ticket numbering change.

Calculate average monthly mileage

I have a list of fleet vehicles that I'm attempting to calculate the average monthly and yearly mileage of.
For example, vehicle 1970 was manufactured in 2015, and has a current odometer of 105,341. That means the truck is 2 years or 24 months old. So the yearly average is 52,670 miles and the monthly average is 4,389.
I'm selecting the vehicle number, year of mfg., and the current odometer reading.
The field M.ManufacturerYear is data type int and O.MeterLevel is data type varchar
How would I write the calculated fields to return the monthly and yearly average for each vehicle in the list?
Perhaps an alternative of calculating the actual number of months and then annualizing (or normalizing) the results.
In the example below, Vehicle 2020 is only 7 months old, but the annualized mileage is greater than Vehicle 1970
Example
Declare #YourTable Table ([Vehicle] varchar(50),ManufacturerYear int,[Odometer] int)
Insert Into #YourTable Values
(1970,2015,105341)
,(2020,2017,25253)
Select *
,NbrMonths = datediff(month,left(ManufacturerYear,4) +'0101',GetDate())
,PerMonth = [Odometer] / datediff(month,left(ManufacturerYear,4) +'0101',GetDate())
,Annualized = ([Odometer] / datediff(month,left(ManufacturerYear,4) +'0101',GetDate()) ) * 12
From #YourTable
Returns
The below sample code is for similar scenario in MS SQL Server.
CREATE TABLE #Vehicle
(
VehicldId int,
YearOfManufacture smallint,
TotalMiles int,
AverageYearlyMiles AS TotalMiles / (YEAR(GETDATE()) - YearOfManufacture),
AverageMonthlyMiles AS TotalMiles / ((YEAR(GETDATE()) - YearOfManufacture) * 12 + MONTH(GETDATE()))
)
insert into #Vehicle(VehicldId,YearOfManufacture,TotalMiles)
values ( 1970,2015,105400)
SELECT * FROM #Vehicle

update 1 table from another table by next earliest date

I have 2 tables: budget and budget_rate:
Budget Table
resource period hours dollars
-------- ------ ----- -------
ADMIN03 01/31/16 160 8000
ADMIN03 02/28/16 150 7500
Rate Table
resource rate eff_date
-------- ---- --------
ADMIN03 50.00 01/01/16
ADMIN03 52.50 01/01/17
When the rates change in the rate table, I need to update the budget based on the rate that matches the resource name and is the first rate record earlier than the budget record.
Can this be accomplished with a single UPDATE?
Something like:
update b
set b.dollars = b.hours*r.rate
from
budget b join rate r on
b.resource = r.resource and
b.period >= r.eff_date
I assume rate table is realtive small, so I would recalculate it to have range columns.
with oRates as (
select resource,
rate,
eff_date,
ROW_NUMBER() over(partition by resource order by eff_date desc) rn
from Rates
),
pRates as (
select r1.resource,
r1.rate,
r1.eff_date from_date,
isnull(r2.eff_date,'2070-01-01') to_date
from oRates r1
left join oRates r2 on (r1.rn = r2.rn+1)
)
update b
set dollars = hours * r.rate
from Budget b
join pRates r on (b.resource = r.resource
and b.period >= from_date
and b.period < to_date)
One possible solution is using a computed column instead of some sort of manual update.
An example of how this could be done can be seen here: formula for computed column based on different table's column
For a working example with your data, you'd create a function like this:
CREATE FUNCTION dbo.ufn_BudgetDollars (#resource NVARCHAR(255), #date DATE, #hours INT)
RETURNS DECIMAL(10, 2)
AS BEGIN
DECLARE #out DECIMAL(10, 2);
SELECT #out = #hours * rate
FROM (
SELECT rate, ROW_NUMBER() OVER (ORDER BY eff_date DESC) rn
FROM tblRate
WHERE eff_date <= #date
AND resource = #resource) T
WHERE RN = 1;
RETURN #out;
END
GO
When you've created your function, you would want to drop and recreate the Dollars column on the budget table...
ALTER TABLE tblBudget DROP COLUMN Dollars;
ALTER TABLE tblBudget ADD Dollars AS dbo.ufn_BudgetDollars(resource, Period, Hours);
GO

How to do create a table in SQL and do headcounts in the respective hours

We are trying to do an analysis of how many staff are there in each department in every hour for trending and forecasting purposes.
The image below is the outcome I would like to get
http://i.stack.imgur.com/iMtaP.png
2am means the number of employees clocked in from 2:00am to 2:59am
We would be putting the query into tableau software for analyzing. Btw I am using mssql 2014.
We have the following columns to do the query
SHIFTA_Start = Clock in Time (VARCHAR)
SHIFTA_End = Clock out Time (VARCHAR)
EMPLOYEENAME = Name of the Employee
DEPARTMENT = Department of the Employee
ATTENDANCEDATE = Date the employee come for work (VARCHAR)
WEEKDAYSTR = Mon, Tues, Wednesday, Thursday, Friday
I hope this helps, modify based on your requirement.
SELECT DEPARTMENT,
(SELECT COUNT(EMPLOYEENAME) FROM TABLE WHERE DATEPART(HH,SHIFTA_START) <= 1 AND DATEPART(HH,SHIFTA_END) >= 2 AND DEPARTMENT = T.DEPARTMENT) AS '2AM',
(SELECT COUNT(EMPLOYEENAME) FROM TABLE WHERE DATEPART(HH,SHIFTA_START) <= 2 AND DATEPART(HH,SHIFTA_END) >= 3 AND DEPARTMENT = T.DEPARTMENT) AS '3AM',
.
.
.
.
FROM TABLE T
WHERE ATTENDANCEDATE = GETDATE()
GROUP BY DEPARTMENT
ORDER BY DEPARTMENT

Query to get sum of an employees commission

Query to get total commissions for an employee, and update their totalCommission column in the employee table.
This query is run every few days (batch).
The rules:
1. an employee can only get a maximum of $100/day of commision, if they get more than $100 it just gets set to $100.
Tables:
Employee
(employeeID INT PK, totalCommissions INT, username, ...)
Sale
(saleID INT PK, employeeID INT FK, saleTotal, commission, created DATETIME)
Using SQL Server 2005.
So this query will have to group by day I presume, and use a case statement to set the daily commision to $100 if the sum is > 100 for that day, and then set the total SUM for all days to the Employee.TotalCommission column.
assuming you are limiting the dates somewhere using value of "somedate-goes-here":
update employee set totalcommissions = totalc
from
(
-------------------------------------
-- sum capped commissions by employee
-------------------------------------
select employeeID, sum(sum_commissions) as totalc from
(
---------------------------------------
-- make sure sum is capped if necessary
---------------------------------------
select employeeID
, case when sum_of_c > 100 then 100 else sum_of_c as sum_commisions
from
(
-----------------------------------------------
-- get sum of commissions per day per employee
-----------------------------------------------
select employeeID, sum(commission) as sum_of_c from sale
where created > "somedate-goes-here"
group by employeeID, day(created)
) as x
) as c
group by employeeID
) y
inner join employee on employee.employeeID = y.employeeID

Resources