Oracle SQL for commission per employee per week - sql

Here is the sample data in an Oracle 11g database I am trying to work with to come up with a SQL query to return commission earned by each employee per week. If an employee did not earn a commission in a week, then it should display 0 as in the commission_earned column. (Assuming the week start on Monday)
SQL> select * from SALES;
EMPLID PRODUCT_TYPE PRODUCTID SALE_AMOUNT COMMISSION_EARNED SALE_DATE
1001 Desktop 55355251 750 45 02-MAY-16
1002 Desktop 2332134 600 30 02-MAY-16
1001 Laptop 773643 1200 65 02-MAY-16
1003 Camera 5546232 450 25 03-MAY-16
1002 Printer 445321 150 15 04-MAY-16
1001 Printer 445321 150 15 10-MAY-16
1003 Camera 5546232 450 25 10-MAY-16
I am trying to come up with a sql that would return the total commission earned by each employee per week. I would appreciate any help or pointers.
WEEKOF EMPLID COMMISSION_EARNED
02-MAY-16 1001 110
02-MAY-16 1002 45
02-MAY-16 1003 25
09-MAY-16 1001 15
09-MAY-16 1002 0
09-MAY-16 1003 25
I came up with the below sql but it does not display a row for emplid 1002 with commision_earned as 0 for the week starting with 09-MAY-16
SQL> select trunc(sale_date,'IW') WEEKOF,emplid,sum(COMMISSION_EARNED) COMMISSION_EARNED from sales group by trunc(sale_date,'IW'),emplid order by trunc(sale_date,'IW'),emplid;
WEEKOF EMPLID COMMISSION_EARNED
02-MAY-16 1001 110
02-MAY-16 1002 45
02-MAY-16 1003 25
09-MAY-16 1001 15
09-MAY-16 1003 25

You can generate all the rows with a cross join and then use left join to get the information from the table:
select w.wk, e.emplid,
coalesce(sum(t.commission_earned), 0) as commission_earned
from (select distinct trunc(weekof, 'IW') as wk from test) w cross join
(select distinct emplid from test) e left join
test t
on t.emplid = e.emplid and trunc(t.weekof, 'IW') = w.wk
group by w.wk, e.emplid
order by w.wk, e.emplid;

Related

Need to pick up the SUM OF Tax Amount for the highest Sequence number Per Year, Per SSN, Per employer

Consider Employee table:
Employerid ssn year Seqnumber q1taxamt q2taxamt q3taxamt q4taxamt
1004 101 2013 1 2000 0 0 0
1004 101 2013 2 2000 100 0 0
1004 101 2013 3 2000 100 200 0
1004 101 2013 4 2000 100 200 300
1004 102 2013 1 3000 0 0 0
1004 102 2013 2 3000 200 0 0
1004 102 2013 3 3000 200 300 0
1004 102 2013 4 3000 200 300 400
1004 102 2013 5 3000 200 300 400
Here the transformation rule is we need to pick the highest Seqnumber with respect to each ssn per year per
Employerid and the amounts.
i.e for 10004 for sum(q1taxamt) is 2000 +3000 = 5000
The Logic is ssn 101 has highest seq number of 4 and ssn 102 has highest seq number of 5 so we need to pick those values wrt to employerid
Example:
Want to check for q1taxamt: 2000 +3000 = 5000
Want to check for q4taxamt: 300 +400 = 700
output must be:
Employerid YEAR q1taxamt q2taxamt q3taxamt q4taxamt
10004 2013 5000 300 500 700
The below query is generating wrong result:
Select
Sum(E1.q1taxamt) q1taxamt,
Sum(E1.q2taxamt) q2taxamt,
Sum(E1.q3taxamt) q3taxamt,
Sum(E1.q4taxamt) q4taxamt,
E1.Employerid,
E1.YEAR
from Employee E1
join
(
select
E.Employerid,
MAX(E.seqnumber) seqnumber,
E.YEAR
from Employee E
group by E.Employerid,E.SSn,E.year
)E2
on E1.Employerid=E2.Employerid
AND E1.YEAR=E2.YEAR
and E1.seqnumber=E2.Taxseqnumber
Just use row_number():
select e.*
from (select e.*,
row_number() over (partition by E.Employerid, E.SSn, E.year
order by e.seqnumber desc
) as seqnum
from Employee e
) e
where seqnum = 1;
For best performance, you want an index on Employee(EmployerId, SSN, seqnumber desc).
You missing SSN join predicate between E1 and E2 thats why you are getting wrong result. I think this might be faster than Row_Number method.
Select
Sum(E1.q1taxamt) q1taxamt,
Sum(E1.q2taxamt) q2taxamt,
Sum(E1.q3taxamt) q3taxamt,
Sum(E1.q4taxamt) q4taxamt,
E1.Employerid,
E1.YEAR
from Employee E1
join
(
select
E.Employerid,
E.SSn,
MAX(E.seqnumber) seqnumber,
E.YEAR
from Employee E
group by E.Employerid,E.SSn,E.year
)E2
on E1.Employerid=E2.Employerid
AND E1.YEAR=E2.YEAR
AND E1.SSN = E2.SSN --Here
and E1.seqnumber=E2.Taxseqnumber

Getting value repeated for next year if value is recurring

I have a record for project and release number and I need to repeat the row in next year if value is recurring.
First image is showing the data that I have it
My expected output is:
Explanation of output: In year 2017 value_type ITA has frequency as Recurring so, This value should be repeated in all next year(i.e 2018, 2019 and 2020). like that in year 2018 OC and PA is recurring so it also need to repeated in 2019 and 2020.
For that I created a new view for only recurring value and tried to join that view with base table. But it is not giving me proper result.
Can anyone please help me with this?
Thanks in advance..
DECLARE #EndYear INT =2020 --Also you can get from data by MAX(Year)
;WITH tb(PROJECT_ID,RELEASE_NO,[YEAR],VALUE_TYPE,VAL_DES,COST,RUN_TATE,FREQUENCY)
AS(
SELECT 111,1,2016,'IT','EXPENSE',0,NULL,NULL UNION
SELECT 111,1,2016,'IR','INCOME',10000,NULL,NULL UNION
SELECT 111,1,2016,'OC','EXPENSE',-200000,NULL,NULL UNION
SELECT 111,1,2016,'Vendor','EXPENSE',-5000,NULL,NULL UNION
SELECT 111,1,2017,'BC','INCOME',200000,NULL,NULL UNION
SELECT 111,1,2017,'ITA','INCOME',5000,5000,'Recurring' UNION
SELECT 111,1,2017,'OC','EXPENSE',-200000,NULL,NULL UNION
SELECT 111,1,2018,'OC','EXPENSE',-10000,-10000,'Recurring' UNION
SELECT 111,1,2018,'PA','INCOME',100000,100000,'Recurring' UNION
SELECT 111,1,2019,'icc','INCOME',500,NULL,NULL UNION
SELECT 111,1,2020,NULL,NULL,NULL,NULL,NULL
),Recurring AS (
SELECT tb.PROJECT_ID,tb.RELEASE_NO,tb.VALUE_TYPE,tb.VAL_DES,MIN([YEAR]) AS StartYear,MAX(COST) AS COST,MAX(tb.RUN_TATE) AS RUN_TATE
FROM tb WHERE FREQUENCY='Recurring'
GROUP BY tb.PROJECT_ID,tb.RELEASE_NO,tb.VALUE_TYPE,tb.VAL_DES
)
SELECT * FROM tb union
SELECT r.PROJECT_ID,r.RELEASE_NO,n.number AS [YEAR],r.VALUE_TYPE,r.VAL_DES,r.COST,r.RUN_TATE,NULL AS FREQUENCY FROM
Recurring AS r
OUTER APPLY (
SELECT sv.number FROM master.dbo.spt_values AS sv WHERE sv.type='P' AND sv.number BETWEEN r.StartYear+1 AND #EndYear
)n
PROJECT_ID RELEASE_NO YEAR VALUE_TYPE VAL_DES COST RUN_TATE FREQUENCY
----------- ----------- ----------- ---------- ------- ----------- ----------- ---------
111 1 2016 IR INCOME 10000 NULL NULL
111 1 2016 IT EXPENSE 0 NULL NULL
111 1 2016 OC EXPENSE -200000 NULL NULL
111 1 2016 Vendor EXPENSE -5000 NULL NULL
111 1 2017 BC INCOME 200000 NULL NULL
111 1 2017 ITA INCOME 5000 5000 Recurring
111 1 2017 OC EXPENSE -200000 NULL NULL
111 1 2018 ITA INCOME 5000 5000 NULL
111 1 2018 OC EXPENSE -10000 -10000 Recurring
111 1 2018 PA INCOME 100000 100000 Recurring
111 1 2019 icc INCOME 500 NULL NULL
111 1 2019 ITA INCOME 5000 5000 NULL
111 1 2019 OC EXPENSE -10000 -10000 NULL
111 1 2019 PA INCOME 100000 100000 NULL
111 1 2020 NULL NULL NULL NULL NULL
111 1 2020 ITA INCOME 5000 5000 NULL
111 1 2020 OC EXPENSE -10000 -10000 NULL
111 1 2020 PA INCOME 100000 100000 NULL

Rolling 12 months SUM from latest available data with varchar YearMonth

Sample Schema: ID (varchar 4), YM (varchar 6), Rev(Float) , P_K (ID,YM)
ID YM Rev
1001 201112 150
1001 201211 200
1001 201212 200
1001 201303 500
... ... ...
1001 201605 400
1023 201112 150
1023 201211 200
1023 201212 200
1023 201303 500
... ... ...
1023 201605 700
I need to create a VIEW where Every row should have a SUM of Rev (Revenue) for preceeding 12 months from the YM(Year Month).
I have tried the following query, however it returns data from '201512' backwards. Where I was expecting the YM to be starting from '201603' since that is the latest YM data available in the table.
SELECT
fs.ID,
fs.YM,
(SELECT SUM(fsi.Rev) FROM FSource fsi WHERE fsi.YM >= ((100* (fs.YM / 100) + 1)-100) AND fsi.YM <= fs.YM AND fsi.ID= fs.ID) AS Rev
FROM FSource fs
WHERE RIGHT(fs.ym, 2) = (SELECT COUNT(*) FROM FSource fsi WHERE fsi.YM >= ((100* (fs.ym / 100) + 1)-100) AND fsi.YM <= fs.ym AND fsi.ID= fs.ID)
Any help, what could possibly be wrong hapenning here?
Expected Output:
ID YM Rev
... ... ...
1001 201601 1500
1001 201602 2400
1001 201603 2400
1001 201604 6000
1001 201605 4800 (assuming last 12 months were 400 each, date range "201506 to 201605")
You can approach this using a correlated subquery:
select fs.*,
(select sum(fs2.rev)
from fsource fs2
where fs2.id = fs.id and
cast(fs2.ym as int) <= cast(fs.ym as int) and
cast(fs2.ym as int) > cast(fs.ym as int) - 100
) as rev_12months
from fsource fs;
One problem with your query is this expression ((100* (fs.YM / 100) + 1)-100). For a value such as 201603, it turns into 201501, because SQL Server does integer division. Also, it is a bad idea to rely on implicit conversion.
The rows being returned are determined by the outer where. I have no idea what that logic is supposed to be doing.

Select statement with multiple rows from condition on values in single column affecting more than one column

I have the table below.Using salary as condition I want to get multiple rows. Below is current table call it employee.
empid | name | salary
-----------------------------------
1 A1 alex 20000
2 B2 ben 4500
3 C1 carl 14000
compare the salary to certain fixed values, and every time the salary is larger than the fixed value, show a record in output.Also output a calculated tax column.Below is a step closer to my final result
select e.*,tax= (case when salary<6000 then tax=0.06 *salary,when salary between 6000 and 18000 then tax= 0.06 *(salary -6000),else tax =0 ),m.incometype,
from employee e
left join
(
select 0 as threshold, 101 as incometype
union
select 5999 as threshold, 102 as incometype
union
select 17999 as threshold, 103 as incometype
) m
on e.salary > m.threshold
order by e.empid
Desired ouput would be:
empid | name | salary | incometype | tax
----------------------------------------------
1 A1 alex 20000 101 360
2 A1 alex 20000 102 720
3 A! alex 20000 103 0
4 B2 ben 4500 101 270
5 C1 carl 14000 101 360
6 C1 carl 14000 102 480
this is a question further to Select statement with multiple rows from condition on values in single column
this may help you
select e.*,
case
when salary<6000 then (0.06*salary)
when salary between 6000 and 1800 then (0.06*(salary -6000))
when m.incometype=103 then 0
end as tax
,m.incometype,
from employee e
left join
(
select 0 as threshold, 101 as incometype
union
select 5999 as threshold, 102 as incometype
union
select 17999 as threshold, 103 as incometype
) m
on e.salary > m.threshold
order by e.empid

Joins and Loops in SQL Server 2008

How to join the below tables to get result like in "Result" table:
Table: Invoice
Inv_No Fk_Rep_ID Inv_Date Inv_Amt
3000 202 10/1/2014 35
3001 194 11/1/2014 40
3002 180 15/1/2014 55
Table :Return
Return_ID FK_Rep_ID Ret_Date Ret_Amt
2000 202 17/1/2014 67
2001 194 15/1/2015 43
Table: Credit
Credit_ID FK_Rep_ID credit_Date credit_Amnt
1000 NULL 4/2/2014 60
1001 202 5/2/2014 12
Table: Debit
Debit_ID FK_Rep_ID Debit_Date Debit_Amnt
400 NULL 4/5/2014 600
4001 194 5/5/2014 110
Table:Receipt_Items
Fk_Rec_No FK_Item_No Item_Type Rec_Item_ID
7787 1000 2 1
7788 2000 1 1
7788 3000 0 2
7788 3001 0 3
7788 3002 0 4
7788 4000 3 5
7788 4001 3 6
7789 1001 2 1
Table :Sales_Rep
Rep_ID Rep_Name
180 Vinu
194 Bibin
202 Salman
Result
Fk_Rec_No Fk_Item_No Item_Type Rep_Name Item_Date Item_Amt
7787 1000 Credit NULL 4/2/2014 -60
7788 2000 Return salman 15/1/2014 -67
7788 3000 Invoice salman 10/1/2014 35
7788 3001 Invoice Bibin 11/1/2014 40
7788 3002 Invoice Vinu 12/1/2014 55
7788 4000 Debit NULL 4/5/2014 600
7788 4001 Debit Bibin 5/5/2014 110
7789 1001 Credit Salman 5/2/2014 -12
Query :
SELECT tt.*,SR.Rep_Name
FROM(SELECT
fk_receipt_no
,fk_item_no
,CASE Item_type
WHEN 0 THEN 'INVOICE'
WHEN 1 THEN 'Return'
WHEN 2 THEN 'Credit'
WHEN 3 THEN 'Debit'
END as ITEM_type,
Case Item_type when 1 then '-'+Cast(Item_Amnt as varchar(50))
when 2 then '-'+Cast(Item_Amnt as varchar(50))
else Cast(Item_Amnt as varchar(50)) End Item_Amnt
,COALESCE(R.FK_Rep_ID,C.FK_Rep_ID,I.FK_Rep_ID) as FK_Rep_ID
,COALESCE(R.Ret_Date,C.Note_Date,I.Inv_Date) as Item_Date
FROM Recp_Item RI LEFT JOIN [Return] R ON RI.FK_Item_no=R.Return_ID
LEFT JOIN Credit C ON RI.FK_Item_No=C.Note_ID
LEFT JOIN Invoice I ON RI.FK_Item_No=I.Inv_No
) tt LEFT JOIN [Sales Rep] SR ON SR.Rep_ID=tt.FK_Rep_ID
You probably should mention that FK_Item_No refers sometimes to different things, like Credit_ID. This kind of multipurpose FK almost always results in a union for each type of item it could represent.
This is pseudo code, I expect you to provide all the tedious join criterias since you should be capable of doing so.
Notice left joins are used to the Rep table since you have some null FK's
In each select aliases are used to normalize the column names such as credit_amnt => Item_Amt. Technically this is only required for the first select in the join so long as the others are in the same order, but I usually do it for all unions for readability.
Select * From
(
Select ri.Fk_Rec_No, Credit_ID as Fk_Item_No, it.Name as Item_Type,
r.Rep_Name, c.credit_Date as Item_Date, c.credit_Amnt as Item_Amt
From Credit c inner join Receipt_Items ri left join Rep r
--join with your item type table you don't show
Union
Select ri.Fk_Rec_No, Debit_ID as Fk_Item_No, it.Name as Item_Type,
r.Rep_Name, c.Debit_Date as Item_Date, d.Debit_Amnt as Item_Amt
From Debit d inner join Receipt_Items ri left join Rep r
--join with your item type table you don't show
Union
...
) as typesUnion
Order By Fk_Rec_No, Fk_Item_No