Is there a way to get an employee's annual salary using their FTE in a SQL query?
This is the query to get the salary. How do I incorporate the FTE component?
SELECT papf.employee_number,papf.full_name,pj.NAME job,
pap.NAME as Designation ,pg.NAME as Grade , haou.NAME
ORGANIZATION,ppp.creation_date createDate,
ppp.PROPOSED_SALARY as salary
FROM per_all_people_f papf
,per_all_assignments_f paaf
,per_jobs pj
,per_grades pg
,hr_all_organization_units haou
,per_position_definitions ppd
,per_all_positions pap
,per_pay_proposals ppp
WHERE SYSDATE BETWEEN papf.effective_start_date AND papf.effective_end_date
AND papf.current_employee_flag = 'Y'
AND papf.employee_number IS NOT NULL
AND paaf.person_id = papf.person_id
AND SYSDATE BETWEEN paaf.effective_start_date AND paaf.effective_end_date
AND paaf.job_id = pj.job_id
AND paaf.organization_id = haou.organization_id
AND paaf.grade_id = pg.grade_id
AND paaf.position_id = pap.position_id
AND pap.position_definition_id = ppd.position_definition_id
AND ppp.pay_proposal_id in (SELECT MAX (pay_proposal_id)
FROM per_pay_proposals
WHERE assignment_id = paaf.assignment_id)
order by to_number(papf.employee_number)
Related
I have created the above query which give me the Bonus tagged to the person as of sysdate.
select
person_number ,
peef.effective_start_Date,
peef.value Amount
from
per_all_people_f papf,
pay_element_entries_f peef
where
papf.person_id = peef.person_id
and PEEF.element_name in ('Bonus')
and sysdate between peef.effective_start_Date and peef.effective_end_Date
I want to tweak the above query to get the Amount for past three years as of 31/3 i.e. instead of sysdate as of 31/3/2021, 31/03/2020,31/03/2019
Output like -
Person_NUMBER effective_start_Date current_Amount 2021_AMOUNT 2020_AMOUNT 2019_AMOUNT
How can i tweak the same query and change the sysdate condition to look for data for past three years as well for the 2021_amount, 2020_amount and 2019_amount column
You can move the last line to the SELECT list as conditionals such as
SELECT person_number, peef.effective_start_Date,
peef.value AS current_amount,
CASE WHEN date'2021-03-31' BETWEEN peef.effective_start_Date AND peef.effective_end_Date
THEN peef.value
END AS 2021_amount,
CASE WHEN date'2020-03-31' BETWEEN peef.effective_start_Date AND peef.effective_end_Date
THEN peef.value
END AS 2020_amount,
CASE WHEN date'2019-03-31' BETWEEN peef.effective_start_Date AND peef.effective_end_Date
THEN peef.value
END AS 2019_amount
FROM per_all_people_f papf
JOIN pay_element_entries_f peef
ON peef.person_id = papf.person_id
WHERE peef.element_name = 'Bonus'
in order to get the currently displayed result, but in this case there will be multiple lines with NULL values for amount columns. I suspect that you need to get aggregated results in order to show the summed up amounts, then consider adding SUM() aggregation such as
SELECT person_number, peef.effective_start_Date,
SUM( peef.value ) AS current_amount,
SUM( CASE WHEN date'2021-03-31' BETWEEN peef.effective_start_Date AND peef.effective_end_Date
THEN peef.value
END ) AS 2021_amount,
SUM( CASE WHEN date'2020-03-31' BETWEEN peef.effective_start_Date AND peef.effective_end_Date
THEN peef.value
END ) AS 2020_amount,
SUM( CASE WHEN date'2019-03-31' BETWEEN peef.effective_start_Date AND peef.effective_end_Date
THEN peef.value
END ) AS 2019_amount
FROM per_all_people_f papf
JOIN pay_element_entries_f peef
ON peef.person_id = papf.person_id
WHERE peef.element_name = 'Bonus'
GROUP BY person_number, peef.effective_start_Date
I have an Oracle Query below
select papf.person_number, to_char(hrcd.SUBMITTED_DATE, 'DD-Mon-YYYY','NLS_DATE_LANGUAGE = American') as "Resignation Date", paam.last_update_date as assignmentupdate, hrcd.last_update_date as hrcdupdate, hth.last_update_date as hthupdate
from
per_all_people_f papf, per_all_assignments_m paam, hrc_txn_header hth, HRC_TXN_DATA hrcd
where
papf.person_id=paam.person_id
and paam.assignment_type IN ('E','C')
and paam.assignment_status_type in ('ACTIVE')
and paam.primary_flag = 'Y'
and paam.EFFECTIVE_LATEST_CHANGE ='Y'
and trunc(sysdate) between trunc(paam.effective_start_date) and trunc(paam.effective_end_date)
and trunc(sysdate) between trunc(papf.effective_start_date) and trunc(papf.effective_end_date)
and paam.person_id=hth.subject_id(+)
and paam.assignment_id=hth.object_id(+)
and hth.module_identifier(+) IN ('Resignation','Terminations')
and hrcd.transaction_id(+)=hth.transaction_id
and papf.person_number IN ('901626', '900723', '900846');
Which is giving below result
Now I am Person 900846 has multiple rows coming, now I need to extract the max date from this column for that I added the below logic but this is not working
select papf.person_number, to_char(hrcd.SUBMITTED_DATE, 'DD-Mon-YYYY','NLS_DATE_LANGUAGE = American') as "Resignation Date", paam.last_update_date as assignmentupdate, hrcd.last_update_date as hrcdupdate, hth.last_update_date as hthupdate
from
per_all_people_f papf, per_all_assignments_m paam, hrc_txn_header hth, HRC_TXN_DATA hrcd
where
papf.person_id=paam.person_id
and paam.assignment_type IN ('E','C')
and paam.assignment_status_type in ('ACTIVE')
and paam.primary_flag = 'Y'
and paam.EFFECTIVE_LATEST_CHANGE ='Y'
and trunc(sysdate) between trunc(paam.effective_start_date) and trunc(paam.effective_end_date)
and trunc(sysdate) between trunc(papf.effective_start_date) and trunc(papf.effective_end_date)
and paam.person_id=hth.subject_id(+)
and paam.assignment_id=hth.object_id(+)
and hth.module_identifier(+) IN ('Resignation','Terminations')
and hrcd.transaction_id(+)=hth.transaction_id
and hrcd.SUBMITTED_DATE =
(SELECT MAX(hrcd2.SUBMITTED_DATE)
FROM HRC_TXN_DATA hrcd2, hrc_txn_header hth2, per_all_assignments_m paam2
WHERE hrcd2.TRANSACTION_ID = hrcd.TRANSACTION_ID
AND hrcd2.transaction_id=hth2.transaction_id
and hth2.module_identifier IN ('Resignation','Terminations')
and paam2.assignment_id=hth2.object_id
and paam2.assignment_id=paam.assignment_id
)
and papf.person_number IN ('901626', '900723', '900846');
But now the Output is like below
I am not sure how the outer join will be added in the second query and even after after that the result should 3 lines of data each for employee with max resignation date and blank is resignation date is null
Output should look like below
can someone help me in this?
Thanks,
Shivam
You can use window functions (ROW_NUMBER | RANK | DENSE_RANK | MAX OVER) to rank your rows and only pick the latest per person. E.g.:
select person_number, "Resignation Date", assignmentupdate, hrcdupdate, hthupdate
from
(
select
papf.person_number,
to_char(hrcd.submitted_date, 'DD-Mon-YYYY', 'NLS_DATE_LANGUAGE = American') as "Resignation Date",
paam.last_update_date as assignmentupdate,
hrcd.last_update_date as hrcdupdate,
hth.last_update_date as hthupdate,
hrcd.submitted_date,
max(hrcd.submitted_date) over (partition by papf.person_number) as max_submitted_date
from per_all_people_f papf
join per_all_assignments_m paam on paam.person_id = papf.person_id
left join hrc_txn_header hth on hth.subject_id = paam.person_id
and hth.object_id = paam.assignment_id
and hth.module_identifier IN ('Resignation', 'Terminations')
left join HRC_TXN_DATA hrcd on hrcd.transaction_id = hth.transaction_id
where papf.person_number IN (901626, 900723, 900846)
and paam.assignment_type IN ('E', 'C')
and paam.assignment_status_type in ('ACTIVE')
and paam.primary_flag = 'Y'
and paam.effective_latest_change = 'Y'
and trunc(sysdate) between trunc(paam.effective_start_date) and trunc(paam.effective_end_date)
and trunc(sysdate) between trunc(papf.effective_start_date) and trunc(papf.effective_end_date)
)
where (submitted_date = max_submitted_date)
or (submitted_date is null and max_submitted_date is null)
order by person_number;
I am trying to add two tables and get the total days from two dates. But having the following simple issue: not a single-group group function.
This is what I've tried so far:
SELECT COUNT(status) AS "Present Days",
(SELECT TRUNC(TO_DATE('01/10/2018', 'MM/DD/YYYY') - TO_DATE(k.JOINING_DATE, 'MM/DD/YYYY'))
FROM attendance m
INNER JOIN EMP_OFFICIAL k
ON k.EMPNO = m.EMPNO
WHERE m.empno='EMP00254'
AND m.status='P') AS "Total Days"
FROM attendance
WHERE empno = 'EMP00254'
AND status = 'P';
Can I get the days without using the DUAL?
First off, that subquery is most likely not scalar (it looks like you're assuming multiple rows can come from the attendance table) and second, it contains an unnecessary join..
What I would do instead is something like:
select count(*) as "Present Days",
to_date('01/10/2018', 'mm/dd/yyyy') - k.joining_date "Total Days"
from attendance a
inner join emp_official k on a.empno = k.empno
where a.empno = 'EMP00254'
and a.status = 'P'
group by to_date('01/10/2018', 'mm/dd/yyyy') - k.joining_date;
This does assume that the k.joining_date column is of DATE datatype and that 'k.empno' is a unique column.
If there is only one row in the EMP_OFFICIAL table for each employee then you could do:
SELECT COUNT(a.status) AS "Present Days",
TRUNC( SYSDATE ) - TRUNC( MIN( k.joining_date ) ) AS "Total Days"
FROM attendance a
RIGHT OUTER JOIN EMP_OFFICIAL k
ON ( k.EMPNO = a.EMPNO )
WHERE a.empno = 'EMP00254'
WHERE a.status = 'P';
or you could do the aggregation in a sub-query:
SELECT a."Present Days",
TRUNC( SYSDATE ) - TRUNC( k.joining_date ) AS "Total Days"
FROM (
SELECT EMPNO,
COUNT( status ) AS "Present Days"
FROM attendance
WHERE EMPNO = 'EMP00254'
AND status = 'P'
GROUP BY EMPNO
) a
RIGHT OUTER JOIN EMP_OFFICIAL k
ON ( k.EMPNO = a.EMPNO )
WHERE k.EMPNO = 'EMP00254';
Or you could use UNION ALL to query the two tables and have the result in two rows (rather than two columns):
SELECT 'Present Days' As type,
COUNT(status) AS Days
FROM attendance
WHERE empno = 'EMP00254'
WHERE status = 'P'
UNION ALL
SELECT 'Total Days',
TRUNC( SYSDATE ) - TRUNC( joining_date )
FROM EMP_OFFICIAL
WHERE empno = 'EMP00254';
Either remove COUNT(status) AS "Present Days" part and SELECT inside paranthesis :
SELECT (TRUNC(TO_DATE('01/10/2018', 'MM/DD/YYYY') - TO_DATE(k.JOINING_DATE, 'MM/DD/YYYY')) "time difference" FROM attendance m
INNER JOIN EMP_OFFICIAL k ON k.EMPNO = m.EMPNO where m.empno='EMP00254' and m.status='P') AS "Total Days"
FROM attendance where empno = 'EMP00254' and status = 'P';
OR
use the following (add GROUP BY expression at the end of sql):
SELECT COUNT(status) AS "Present Days",
(TRUNC(TO_DATE('01/10/2018', 'MM/DD/YYYY') - TO_DATE(k.JOINING_DATE, 'MM/DD/YYYY')) "time difference" FROM attendance m
INNER JOIN EMP_OFFICIAL k ON k.EMPNO = m.EMPNO where m.empno='EMP00254' and m.status='P') AS "Total Days"
FROM attendance where empno = 'EMP00254' and status = 'P'
GROUP BY (TRUNC(TO_DATE('01/10/2018', 'MM/DD/YYYY') - TO_DATE(k.JOINING_DATE, 'MM/DD/YYYY'));
Since , groupped and non-groupped items can not be used together.
By the way, you don't need to use dual in your inline select statement like ( SELECT TRUNC(TO_DATE('01/10/2018', 'MM/DD/YYYY') - TO_DATE(k.JOINING_DATE, 'MM/DD/YYYY') FROM DUAL ), just ( TRUNC(TO_DATE('01/10/2018', 'MM/DD/YYYY') - TO_DATE(k.JOINING_DATE, 'MM/DD/YYYY')) is enough.
I need to get all the employees whose age will be 64 between two dates that I specify. Any help would be appreciated.
What I have tried is:
SELECT
papf.person_id,
date_of_birth,
first_name, last_name,
FROM per_all_people_f papf
WHERE
paaf.person_id = NVL(:P_PERSON_ID, paaf.person_id)
AND :START_DATE = TO_DATE(:START_DATE, 'YYYY-MM-DD')
AND :END_DATE = TO_DATE(:END_DATE, 'YYYY-MM-DD')
Try this :-
SELECT person_id, date_of_birth, first_name, last_name FROM per_all_people_f
WHERE floor(months_between(date START_DATE, date END_DATE) /12)=64;
I tried this and it worked:
SELECT papf.person_id,
date_of_birth,
INITCAP (papf.title) || ' ' || papf.first_name || ' ' || papf.last_name,
employee_number,
assignment_id
FROM per_all_people_f papf, per_all_assignments_f paaf
WHERE papf.person_id = paaf.person_id
AND paaf.person_id = NVL(:P_PERSON_ID, paaf.person_id)
AND PAPF.BUSINESS_GROUP_ID = NVL(:P_BUS_ID, PAPF.BUSINESS_GROUP_ID)
AND months_between((:P_START_D), (date_of_birth)) / 12 < 64
AND months_between((:P_END_D), (date_of_birth)) / 12 >= 64
AND SYSDATE BETWEEN papf.effective_start_date AND papf.effective_end_date
AND SYSDATE BETWEEN paaf.effective_start_date AND paaf.effective_end_date
Since your query from Oracle, please try this one:
SELECT PER.FULL_NAME,
PER.DATE_OF_BIRTH,
ROUND(TRUNC(MONTHS_BETWEEN('your custom date', PER.DATE_OF_BIRTH)) / 12,
1)
FROM PER_ALL_PEOPLE_F PER
WHERE TRUNC(SYSDATE) BETWEEN PER.EFFECTIVE_START_DATE AND
PER.EFFECTIVE_END_DATE
AND ROUND(TRUNC(MONTHS_BETWEEN('your custom date', PER.DATE_OF_BIRTH)) /
12, 1) > 64
I wrote this query. But, I am wondering if there is any better/professional way to rewrite this.
Find the employees who would receive bonuses in the current year. The condition for receiving bonus is, he would have to sell a specific category of product of the amount of at least $4000.
select yy.CurrentMonth, yy.ID, yy.Name, sum(yy.commission) as comm_total, sum(yy.bonus) as bonus_total
from
(select sysdate as CurrentMonth, ee.ID, ee.Name, cc.commission, (cc.commission * 25 / 100) as bonus
from employee ee,
(select e.id, pc.category_name, sum(quantity) as qty, pc.commission_rate, sum(quantity*pc.commission_rate) as commission
from sales s, product p, product_category pc, employee e
where to_char(sales_date, 'yyyy') = to_char(sysdate, 'yyyy')
and s.employee_id = e.id
and s.product_id = p.id
and p.product_category_name = pc.category_name
group by pc.category_name, e.id, pc.commission_rate
order by e.id) cc
where ee.ID = cc.id
and cc.commission >=4000
) yy
group by yy.ID, yy.Name, yy.CurrentMonth
Edit: Table schema:
CREATE TABLE "XYZ"."EMPLOYEE"
( "ID" NUMBER,
"NAME" VARCHAR2(20 BYTE),
"AREA_NUMBER" NUMBER,
"EMP_TYPE_NAME" VARCHAR2(20 BYTE)
);
--------------------------------------------------------
-- DDL for Table PRODUCT
--------------------------------------------------------
CREATE TABLE "XYZ"."PRODUCT"
( "ID" NUMBER,
"NAME" VARCHAR2(20 BYTE),
"PRODUCT_CATEGORY_NAME" VARCHAR2(20 BYTE)
) ;
--------------------------------------------------------
-- DDL for Table SALES
--------------------------------------------------------
CREATE TABLE "XYZ"."SALES"
( "RECEIPT_NUMBER" NUMBER,
"SALES_DATE" DATE,
"QUANTITY" NUMBER,
"PRODUCT_ID" NUMBER,
"EMPLOYEE_ID" NUMBER
);
--------------------------------------------------------
-- DDL for Table PRODUCT_CATEGORY
--------------------------------------------------------
CREATE TABLE "XYZ"."PRODUCT_CATEGORY"
( "CATEGORY_NAME" VARCHAR2(20 BYTE),
"COMMISSION_RATE" FLOAT(126)
) ;
You can use multi step cte, use indenation, use JOIN syntax, avoid long lines, capitalize keywords, avoid ordering in subquery and so on:
WITH cte AS
(
SELECT e.id
,pc.category_name
,pc.commission_rate
,SUM(quantity) AS qty
,SUM(quantity * pc.commission_rate) AS commission
FROM sales s
JOIN product p
ON s.product_id = p.id
JOIN product_category pc
ON p.product_category_name = pc.category_name
JOIN employee e
ON s.employee_id = e.id
WHERE TO_CHAR(sales_date, 'yyyy') = TO_CHAR(SYSDATE, 'yyyy')
GROUP BY e.id, pc.category_name, pc.commission_rate
), cte2 AS
(
SELECT SYSDATE AS CurrentMonth
,ee.ID
,ee.Name
,cc.commission
,(cc.commission * 25 / 100) AS bonus
FROM cte cc
JOIN employee ee
ON ee.ID = cc.id
WHERE cc.commission >= 4000
)
SELECT CurrentMonth
,ID
,Name
,SUM(commission) AS comm_total
,SUM(bonus) AS bonus_total
FROM cte2
GROUP BY CurrentMonth, ID, Name;
I believe that you don't need the extra join to the employee table - you're just wanting to exclude the rows where the summed commission is < 4000, right? If so, you can easily do that in the group by query by using the having clause, e.g.:
with sum_categories as (select e.id,
e.name,
pc.category_name,
sum(s.quantity) as qty,
pc.commission_rate,
sum(s.quantity * pc.commission_rate) as commission
from sales s
inner join product p on (s.product_id = p.id)
inner join product_category pc on (p.product_category_name = pc.category_name)
inner join employee e on (s.employee_id = e.id)
where trunc(sales_date, 'yyyy') = trunc(sysdate, 'yyyy')
group by pc.category_name,
e.id,
e.name,
pc.commission_rate
having sum (quantity * pc.commission_rate) >= 4000)
select sysdate currentmonth, -- should this be trunc(sysdate, 'mm')?
yy.id,
yy.name,
sum (yy.commission) as comm_total,
sum (yy.commission * 25 / 100) as bonus_total
from sum_categories yy
group by yy.id,
yy.name;
You'll note that I changed your to_char(sales_date, 'yyyy') = to_char(sysdate, 'yyyy') into trunc(sales_date, 'yyyy') = trunc(sysdate, 'yyyy') because I prefer to keep the comparisons between the correct datatypes (you're comparing two dates, so I like to keep them as dates).