Calculate the leave net entitlement difference between two days - sql

There are two queries i am fetching one which gives todays absence balance
and another which will will give yesterdays absence balance
Todays Net entitlement :
query 1 :
select e.emp_no,
a.absence_code,
a.net_entitlement
from emp_details e,
absence_tab_history a
where a.person_id=e.person_id
and a.history_date=trunc(sysdate);
Yesterday's net entitlemet :
query 2 :
select e.emp_no,
a.absence_code,
a.net_entitlement
from emp_details e,
absence_tab_history a
where a.person_id=e.person_id
and a.history_date=trunc(sysdate)-1;
now query 1 will fetch columns for todays net entitlement such as
emp no. Absence code net entitlement
1 Sick Leave 9
2 Privilege Leave 5
3 Sick Leave 5
now query 2 will fetch columns for yesterdays net entiltement of employees
emp no. Absence code net entitlement
1 Sick Leave 10
2 Privilege Leave 5
3 Sick Leave 6
This means that emp no. 1 and 2's net entitlement have changed and both of them have taken 1 leave each. Now i want to create a query which captures the same ie. only emp 1 and 2
That is if teh net entitlement has changed then displays the changed rows only.
Minus is not working for this and is taking too much time to execute. Kindly help

with present_day
as
(
select 1 as emp_id,'Sick Leave' as code , 9 as net_entitlement from dual
union
select 2 as emp_id,'Privilege Leave' as code , 5 as net_entitlement from dual
union
select 3 as emp_id,'Sick Leave' as code , 5 as net_entitlement from dual
),
yester_day
as
(
select 1 as emp_id,'Sick Leave' as code , 10 as net_entitlement from dual
union
select 2 as emp_id,'Privilege Leave' as code , 5 as net_entitlement from dual
union
select 3 as emp_id,'Sick Leave' as code , 6 as net_entitlement from dual
)
select a.emp_id,a.code,a.net_entitlement,decode(a.net_entitlement-b.net_entitlement,0,'UNCHG','CHNG')
from present_day a,yester_day b
where a.emp_id=b.emp_id and a.code=b.code
and decode(a.net_entitlement-b.net_entitlement,0,'UNCHG','CHNG')='CHNG'
Try the above code and let me know

You need to bring the data together in the tables to do the comparison. Here is one method:
select e.emp_no, coalesce(a.absence_code, ath.absence_code) as absence_code,
a.net_entitlement, ath.net_entitlement
from emp_details e left join
absence_tab_history ath
on ath.person_id = e.person_id and
ath.history_date = trunc(sysdate) - 1 left join
absence_tab a
on a.person_id = e.person_id
where a.person_id is null or
ath.person_id is null or
ath.net_entitlement <> a.net_entitlement;
The first two conditions in the where clause are for new employees who appear and for former employees who leave.

Related

How to show data that's not in a table. SQL ORACLE

I've a data base with two tables.
Table Players Table Wins
ID Name ID Player_won
1 Mick 1 2
2 Frank 2 1
3 Sarah 3 4
4 Eva 4 5
5 Joe 5 1
I need a SQL query which show "The players who have not won any game".
I tried but I don't know even how to begin.
Thank you
You need all the rows from players that don't have corresponding rows in wins. For this you need a left join, filtering for rows that don't join:
select
p.id,
p.name
from Players p
left join Wins w on w.Player_won = p.id
where w.Player_won is null
You can also use not in:
select
id,
name
from Players
where id not in (select Player_won from Wins)
How about the MINUS set operator?
Sample data:
SQL> with players (id, name) as
2 (select 1, 'Mick' from dual union all
3 select 2, 'Ffrank' from dual union all
4 select 3, 'Sarah' from dual union all
5 select 4, 'Eva' from dual union all
6 select 5, 'Joe' from dual
7 ),
8 wins (id, player_won) as
9 (select 1, 2 from dual union all
10 select 2, 1 from dual union all
11 select 3, 4 from dual union all
12 select 4, 5 from dual union all
13 select 5, 1 from dual
14 )
Query begins here:
15 select id from players
16 minus
17 select player_won from wins;
ID
----------
3
SQL>
So, yes ... player 3 didn't win any game so far.
I think you should provide your attempts next time, but here you go:
select p.name
from players p
where not exists (select * from wins w where p.id = w.player_won);
MINUS is not the best option here because of not using indexes and instead performing a full-scan of both tables.
I've a data base with two tables.
You don't show the names or any definition of the tables, leaving me to make an educated guess about their structure.
I tried but I don't know even how to begin.
What exactly did you try? Possibly what you are missing here is the concept of a LEFT OUTER JOIN.
Assuming the tables are named player_table and wins_table, and have column names exactly as you showed, and that the player_won column is intended to express the number of games won by the player of that row's ID, and without knowing whether or not wins_table will have rows for players with zero wins… this should cover it:
select Name
from players_table pt
left join wins_table wt on (pt.ID = wt.ID)
-- Either this player is explicitly specified to have Player_won=0
-- or there is no row for this player ID in the wins table
-- (but excluding the possibility of an explicit NULL value, since its meaning would be unclear)
where Player_won = 0 or wt.ID is null;
As you can see from the variety of answers you've gotten, there are many ways to accomplish this.
One additional way to do this is to use COUNT in a correlated subquery, as in:
SELECT *
FROM PLAYERS p
WHERE 0 = (SELECT COUNT(*)
FROM WINS w
WHERE w.PLAYER_WON = p.ID)
db<>fiddle here
SELECT *
FROM Players p
INNER JOIN Wins w
ON p.ID = w.ID
WHERE w.players_won = 0
I have not done SQL in awhile but I think this might be right if you are looking for players with 0 wins

Find status from separate fact table

This is in snowflake, but I can figure out any other syntax that is similar.
I have a table of employees and the date they received a paycheck
EMP_ID
Check_dt
1
10-7-2021
2
9-28-2021
1
3-1-2021
And a table that has employee history for full/part time status changes, and the date the change was made effective
EMP_ID
Status
Effective Date
1
F
1/1/20201
2
P
1/1/2021
1
P
6/1/2021
(In this example, employee 1 changed from full to part time halfway through the year)
I want to get the status (F/P) of the employee at the time they received their paycheck.
The output I want is:
EMP_ID
Check_dt
Status
1
10-7-2021
P
2
9-28-2021
P
1
3-1-2021
F
Thanks in advance!
Try this
Select empid, case when t1.chkdate<= (Select
max(effect_date) from
table2 where empid=t1.empid) then t1.status) end as
status
From table1 t1

Postgresql How to Calculate between 2 date depends on another table

let's say i have two table like this :
workday_emp
emp_id work_start work_end
1 "2021-04-06" "2021-04-14"
2 "2021-04-27" "2021-05-04"
3 "2021-04-30" "2021-05-07"
holiday_tbl
id name date
1 "holiday 1" "2021-04-07"
2 "holiday 2" "2021-04-28"
3 "holiday 3" "2021-04-29"
i want to show table like this with a query:
emp_id work_start work_end day_holiday
1 "2021-04-06" "2021-04-14" 1
2 "2021-04-27" "2021-05-04" 2
3 "2021-04-30" "2021-05-07" 1
the question is, how to calculate how many "day_holiday" between "work_start" and "work_end" depends to "holiday_tbl" table?
Please try this. For Employee 3 holiday count will 0 not 1 because his work_day starts at april30 but last holiday was apr29.
-- PostgreSQL(v11)
SELECT w.emp_id, w.work_start, w.work_end
, (SELECT COUNT(id)
FROM holiday_tbl
WHERE holiday_date BETWEEN w.work_start AND w.work_end) day_holiday
FROM workday_emp w
Please check from url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=1948691b58ba841b2765d7de383f8df8
This should do the job:
SELECT emp_id, work_start, work_end, COUNT(ht.holiday) holiday_cnt
FROM workday_emp we LEFT JOIN
(
SELECT date holiday
FROM holiday_tbl
) ht ON ht.holiday BETWEEN we.work_start AND we.work_end
GROUP BY 1, 2, 3
ORDER BY 1, 2;
db<>fiddle

How to join 2 queries with different number of records and columns in oracle sql?

I have three tables:
Employee_leave(EmployeeID,Time_Period,leave_type)
Employee(EID,Department,Designation)
leave_eligibility(Department,Designation, LeaveType, LeavesBalance).
I want to fetch the number of leaves availed by a particular employee in each LeaveTypes(Category) so I wrote following query Query1
SELECT LEAVE_TYPE, SUM(TIME_PERIOD)
FROM EMPLOYEE_LEAVE
WHERE EMPLOYEEID=78
GROUP BY LEAVE_TYPE
order by leave_type;
output for Query1
Leave_Type | SUM(Time_Period)
Casual 1
Paid 4
Sick 1
I want to fetch the number of leaves an employee is eligible for each leave_type(category). Following query Query2 gives the desire result.
Select UNIQUE Leavetype,LEAVEBALANCE
from LEAVE_ELIGIBILITY
INNER JOIN EMPLOYEE
ON LEAVE_ELIGIBILITY.DEPARTMENT= EMPLOYEE.DEPARTMENT
AND LEAVE_ELIGIBILITY.DESIGNATION= EMPLOYEE.DESIGNATION
WHERE EID=78
order by leavetype;
output for Query2
LeaveType | LeaveBalance
Casual 10
Paid 15
Privlage 6
Sick 20
Now I want to join these 2 queries Query1 and Query2 or create view which displays records from both queries. Also as you can see from output there are different no. of records from different queries. For a record which is not present in output of query1, it should display 0 in final output. Like in present case there is no record in output of query1 like privlage but it should display 0 in Sum(time_period) in Privlage of final output. I tried creating views of these 2 queries and then joining them, but I'm unable to run final query.
Code for View 1
create or replace view combo_table1 as
Select UNIQUE Leavetype,LEAVEBALANCE,EMPLOYEE.DEPARTMENT,EMPLOYEE.DESIGNATION, EID
from LEAVE_ELIGIBILITY
INNER JOIN EMPLOYEE
ON LEAVE_ELIGIBILITY.DEPARTMENT= EMPLOYEE.DEPARTMENT
AND LEAVE_ELIGIBILITY.DESIGNATION= EMPLOYEE.DESIGNATION
WHERE EID='78';
Code for View 2
create or replace view combo_table2 as
SELECT LEAVE_TYPE, SUM(TIME_PERIOD) AS Leave_Availed
FROM EMPLOYEE_LEAVE
WHERE EMPLOYEEID='78'
GROUP BY LEAVE_TYPE;
Code for joining 2 views
SELECT combo_table1.Leavetype, combo_table1.LEAVEBALANCE, combo_table2.leave_availed
FROM combo_table1 v1
INNER JOIN combo_table2 v2
ON v1.Leavetype = v2.LEAVE_TYPE;
But I'm getting "%s: invalid identifier" while executing the above query. Also I know I can't use union as it requires same column which here it is not.
I'm using Oracle 11g, so please answer accordingly.
Thanks in advance.
Desired final output
LeaveType | LeaveBalance | Sum(Time_period)
Casual 10 1
Paid 15 4
Privlage 6 0
Sick 20 1
To get the final desired output ...
"For a record which is not present in output of query1, it should display 0 in final output. "
... use an outer join to tie the taken leave records to the other tables. This will give zero time_duration for leave types which the employee has not taken.
select emp.Employee_ID
, le.leavetype
, le.leavebalance
, sum (el.Time_Duration) as total_Time_Duration
from employee emp
inner join leave_eligibility le
on le.department= emp.department
and le.designation= emp.designation
left outer join Employee_leave el
on el.EmployeeID = emp.Employee_ID
and el.leave_type = le.leavetype
group by emp.Employee_ID
, le.leavetype
, le.leavebalance
;
Your immediate problem:
I'm getting "%s: invalid identifier"
Your view has references to a column EID although none of your posted tables have a column of that name. Likewise there is confusion between Time_Duration and time_period.
More generally, you will find life considerably easier if you use the exact same name for common columns (i.e. consistently use either employee_id or employeeid, don't chop and change).
Try this examle:
with t as (
select 'Casual' as Leave_Type, 1 as Time_Period, 0 as LeaveBalance from dual
union all
select 'Paid', 4,0 from dual
union all
select 'Sick', 1,0 from dual),
t1 as (
select 'Casual' as Leave_Type, 0 as Time_Period, 10 as LeaveBalance from dual
union all
select 'Paid', 0, 15 from dual
union all
select 'Privlage', 0, 6 from dual
union all
select 'Sick', 0, 20 from dual)
select Leave_Type, sum(Time_Period), sum(LeaveBalance)
from(
select *
from t
UNION ALL
select * from t1
)
group by Leave_Type
Ok, edit:
create or replace view combo_table1 as
Select UNIQUE Leavetype, 0 AS Leave_Availed, LEAVEBALANCE
from LEAVE_ELIGIBILITY INNER JOIN EMPLOYEE ON LEAVE_ELIGIBILITY.DEPARTMENT= EMPLOYEE.DEPARTMENT AND LEAVE_ELIGIBILITY.DESIGNATION= EMPLOYEE.DESIGNATION
WHERE EID='78';
create or replace view combo_table2 as
SELECT LEAVE_TYPE as Leavetype, SUM(TIME_PERIOD) AS Leave_Availed, 0 as LEAVEBALANCE
FROM EMPLOYEE_LEAVE
WHERE EMPLOYEEID='78'
GROUP BY LEAVE_TYPE, LEAVEBALANCE;
SELECT Leavetype, sum(LEAVEBALANCE), sum(leave_availed)
FROM (
select *
from combo_table1
UNION ALL
select * from combo_table2
)
group by Leavetype;

Find Gap between dates ranges SQL Oracle

l want to get the gap between dates range via SQL query lets see the situation:
l have table employees like : Every month the employee deserve payment
ID Name From_date To_date Paid_Amount`
1 ali 01/01/2002 31/01/2002 300
2 ali 01/02/2002 28/02/2002 300
3 ali 01/04/2002 30/04/2002 300
4 ali 01/05/2002 31/05/2002 300
5 ali 01/07/2002 31/07/2002 300
Now, we notice there are no payments in March and June
so, how by SQL query I can't get these months ??
Try this,
with mine(ID,Name,From_date,To_date,Paid_Amount) as
(
select 1,'ali','01/01/2002','31/01/2002',300 from dual union all
select 2,'ali','01/02/2002','28/02/2002',300 from dual union all
select 3,'ali','01/04/2002','30/04/2002',300 from dual union all
select 4,'ali','01/05/2002','31/05/2002',300 from dual union all
select 5,'ali','01/07/2002','31/07/2002',300 from dual
),
gtfirst (fromdt,todt) as (
select min(to_Date(from_Date,'dd/mm/yyyy')) fromdt,max(to_Date(to_Date,'dd/mm/yyyy')) todt from mine
),
dualtbl(first,last,fromdt,todt) as
(
select * from(select TRUNC(ADD_MONTHS(fromdt, rownum-1), 'MM') AS first,TRUNC(LAST_DAY(ADD_MONTHS(fromdt, rownum-1))) AS last,fromdt,todt from gtfirst connect by level <=12)
where first between fromdt and todt and last between fromdt and todt
)
select to_char(first,'month') no_payment_date from dualtbl where first not in (select to_Date(from_Date,'dd/mm/yyyy') from mine)
and first not in (select to_Date(to_date,'dd/mm/yyyy') from mine)
If you want to get the date difference between one payment date and the previous payment date and the ID field is sequential, then you may simply join back to the table and select the previous row.
SELECT X.From_date, Y.From_date, Y.From_date - X.From_date Difference
FROM Employees X
LEFT OUTER JOIN Employees Y ON Y.ID = X.ID - 1
If the ID field is not sequential, then you can use a similar method, but build a temporary table with a row index that you can use to join back to the previous payment.