Query to get sum of an employees commission - sql-server

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

Related

Write Query That Consider Date Interval

I have a table that contains Transactions of Customers.
I should Find Customers That had have at least 2 transaction with amount>20000 in Three consecutive days each month.
For example , Today is 2022/03/12 , I should Gather Data Of Transactions From 2022/02/13 To 2022/03/12, Then check These Data and See If a Customer had at least 2 Transaction With Amount>=20000 in Three consecutive days.
For Example, Consider Below Table:
Id
CustomerId
Transactiondate
Amount
1
1
2022-01-01
50000
2
2
2022_02_01
20000
3
3
2022_03_05
30000
4
3
2022_03_07
40000
5
2
2022_03_07
20000
6
4
2022_03_07
30000
7
4
2022_03_07
30000
The Out Put Should be : CustomerId =3 and CustomerId=4
I write query that Find Customer For Special day , but i don't know how to find these customers in one month with out using loop.
the query for special day is:
With cte (select customerid, amount, TransactionDate,Dateadd(day,-2,TransactionDate) as PrevDate
From Transaction
Where TransactionDate=2022-03-12)
Select CustomerId,Count(*)
From Cte
Where
TransactionDate>=Prevdate and TransactionDate<=TransactionDate
And Amount>=20000
Group By CustomerId
Having count(*)>=2
Hi there are many options how to achieve this.
I think that easies (from perfomance maybe not) is using LAG function:
WITH lagged_days AS (
SELECT
ISNULL(LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
,*
FROM Transaction
), valid_cust_base as (
SELECT
*
FROM lagged_days
WHERE DATEPART(MONTH, lagged) = DATEPART(MONTH, Transactiondate)
AND datediff(day, Transactiondate, lagged_dt) <= 3
AND Amount >= 20000
)
SELECT
CustomerID
FROM valid_cust_base
GROUP BY CustomerID
HAVING COUNT(*) >= 2
First I have created lagged TransactionDate over customer (I assume that id is incremental). Then I have Selected only transactions within one month, with amount >= 20000 and where date difference between transaction is less then 4 days. Then just select customers who had more than 1 transaction.
In LAG First value is always missing per Customer missing, but you still need to be able say: 1st and 2nd transaction are within 3 days. Thats why I am replacing first NULL value with LEAD. It doesn't matter if you use:
ISNULL(LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
OR
ISNULL(LEAD(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id),
LAG(Transactiondate) OVER(PARTITION BY CustomerID ORDER BY id)) lagged_dt
The main goal is to have for each transaction closest TransactionDate.

Payroll computation

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)

Displaying all columns in SQL and also sum of columns with same ID in the last Repeating row

I have 2 tables
OrderDetails:
Id Name type Quantity
------------------------------------------
2009 john a 10
2009 john a 20
2010 sam b 25
2011 sam c 50
2012 sam d 30
ValueDetails:
Id Value
-------------------
2009 300
2010 500
2011 200
2012 100
I need to get an output which displays the data as such :
Id Name type Quantity Price
-------------------------------------------------
2009 john a 10
2009 john a 20 9000
2010 sam b 25
2011 sam c 50
2012 sam d 30 25500
The price is calculated by Value x Quantity and the sum of the values is displayed in the last repeating row of the given Name.
I tired to use sum and group by but I get only two rows. I need to display all 5 rows. How can I write this query?
You can use Row_Number with max of Row_Number to get this formatted sum
;with cte as (
select od.*, sm= sum( od.Quantity*vd.value ) over (partition by Name),
RowN = row_number() over(partition by Name order by od.id)
from #yourOrderDetails od
inner join #yourValueDetails vd
on od.Id = vd.Id
)
select Id, Name, Type, Quantity,
case when max(RowN) over(partition by Name) = row_number() over(partition by Name order by Id)
then sm else null end as ActualSum
from cte
Your input tables:
create table #yourOrderDetails (Id int, Name varchar(20), type varchar(2), Quantity int)
insert into #yourOrderDetails (Id, Name, type, Quantity) values
(2009 ,'john','a', 10 )
,(2009 ,'john','a', 20 ) ,(2010 ,'sam ','b', 25 )
,(2011 ,'sam ','c', 50 ) ,(2012 ,'sam ','d', 30 )
create table #yourValueDetails(Id int, Value Int)
insert into #yourValueDetails(Id, value) values
( 2009 , 300 ) ,( 2010 , 500 )
,( 2011 , 200 ) ,( 2012 , 100 )
SELECT a.ID,
a.Name,
a.Type,
a.quantity,
price = (a.quantity * b.price)
FROM OrderDetails a LEFT JOIN
ValueDetails b on a.id = b.id
This will put the price on every row. If you want to do a SUM by Id,Name and Type it's not going to show the individual records like you show them above. If you want to put a SUM on one of the lines that share the same Id, Name and Type then you'd need a rule to figure out which one and then you could probably use a CASE statement to decide on which line you want to show the SUM total.

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

TSql: Trouble with join

I am trying to write a join query but can't seem to filter it out. I'm selecting an invoice table and and applied payments table. I want to get the balance of all invoice totals amount - applied amounts. I can get the applied amounts fine using sum but when I try to get the total invoice amount, it is too high because its pulling multiple invoice results if more than one payment has been applied to it.
My results:
Invoice No | Amount | Paid
----------------------------
1 | 10 | 5
1 | 10 | 2
2 | 50 | 50
How do I select the sum invoice amount for unique invoice numbers?.
Query Overview:
Select sum(invoiceamount) - sum(appliedamount) as balance
FROM invoice
LEFT JOIN invoicepayments ON invoice.invoiceid = invoicepayments.invoiceid
You're actually looking for a very simple use of GROUP BY. You want to group every result that is the same Invoice/Amount, and then subtract the total (SUM) of the Paid column for that group from the Amount you are grouping on.
SELECT SUM(balance) FROM
(
SELECT invoiceamount - SUM(appliedamount) as balance
FROM invoice
GROUP BY invoiceid, invoiceamount
) balances
You can do it with CTE where you first calculate amount paid on each invoice and than join it to invoices to figure out what is left to pay for each invoice.
;WITH InvoicePay
AS (
SELECT invoiceid
,SUM(appliedamount) AS totalpaid
FROM invoicepayments
GROUP BY invoiceid
)
SELECT i.invoiceID
,i.invoiceamount - totalpaid as Balance
FROM Invoice AS i
JOIN InvoicePay AS ip
ON i.invoiceid = ip.invoiceid

Resources