SQL help needed (oracle application express) - sql

Given this information
Among all projects chen work on, list the name of project that has lowest budget.
EMPID NAME SALARY DID
---------------------------
1 kevin 32000 2
2 joan 42000 1
3 brian 37000 3
4 larry 82000 5
5 harry 92000 4
6 peter 45000 2
7 peter 68000 3
8 smith 39000 4
9 chen 71000 1
10 kim 46000 5
11 smith 46000 1
PID EMPID HOURS
-----------------
3 1 30
2 3 40
5 4 30
6 6 60
4 3 70
2 4 45
5 3 90
3 3 100
6 8 30
4 4 30
5 8 30
6 7 30
6 9 40
5 9 50
4 6 45
2 7 30
2 8 30
2 9 30
1 9 30
1 8 30
1 7 30
1 5 30
1 6 30
2 6 30
PID PNAME BUDGET DID
---------------------------------------
1 DB development 8000 2
2 network development 6000 2
3 Web development 5000 3
4 Wireless development 5000 1
5 security system 6000 4
6 system development 7000 1
This is what I've written so far:
select min(budget), pname
from employee e, workon w, project p
where e.empid = w.empid and p.pid = w.pid and name = 'chen'
group by pname
Which gives me
MIN(BUDGET) PNAME
--------------------------
8000 DB development
6000 security system
6000 network development
7000 system development
How can I select just the lowest (the minimum budget) from these values? Thanks for any help.

use explicit join syntax,
Here is one way using analytic function row_number, sequence number given based on budget with lowest being the first.
with cte
as
(
select row_number() over ( order by budget asc) as rn, pname, budget
from employee e
join workon w
on e.empid = w.empid
join project p
on p.pid = w.pid and name = 'chen'
)
select pname, budget from cte where rn =1

select budgets.budget, budgets.pname
from
(
select min(budget) as budget, pname
from employee e, workon w, project p
where e.empid = w.empid and p.pid = w.pid and name = 'chen'
group by pname
order by budget asc
) budgets
where rownum = 1

Related

Subtract grouped aggregate column by another in 3 table join query

I'm pretty new to joinings and advanced querying, what I want to do is to join three tables to make an summary of how many hours an employee has spent on courses (course data is omitted from examples).
!-SQL query is below the example table-!
The query must show:
A unique set of employee name.
Their individual allocated hours.
A sum of their hours spent
And return a final new column showing the allowance left.
"employees" table
id
employee_id
1
"Annachiara Darius"
2
"Samar Rajani"
3
"Taonga Eric"
4
"Tycho Sigdag"
5
"Naevius Matvei"
6
"Theophania Eglantine"
7
"Boro Stanislav"
"accounting" table where hours are recorded
id
employee_id
hours_done
1
1
2.50
2
1
2.80
3
2
5.60
4
2
3.30
5
4
4.50
6
5
8.90
7
6
7.60
8
3
6.50
9
7
1.00
10
5
10.30
11
7
11.50
12
5
5.60
13
7
100.00
14
2
30.00
"allocation" table
id
employee_id
hours_allocated
1
1
12
2
2
16
3
3
20
4
4
15
5
5
10
6
6
7
7
7
8
SELECT ACCOUNTING.EMPLOYEE_ID AS EMPLOYEE_ID,
EMPLOYEE.EMPLOYEE_NAME AS EMPLOYEE_NAME,
ALLOCATED.HOURS_ALLOCATED,
SUM(ACCOUNTING.HOURS_DONE) AS HOURS_SPENT,
SUM(ALLOCATED.HOURS_ALLOCATED - ACCOUNTING.HOURS_DONE) AS ALLOWANCE
FROM PUBLIC.ACCOUNTING ACCOUNTING
INNER JOIN
(SELECT EMPLOYEE_NAME,
EMPLOYEE_ID
FROM PUBLIC.EMPLOYEES GROUP
BY EMPLOYEE_ID) EMPLOYEE ON EMPLOYEE.EMPLOYEE_ID = ACCOUNTING.EMPLOYEE_ID
INNER JOIN
(SELECT HOURS_ALLOCATED,
EMPLOYEE_ID
FROM PUBLIC.ALLOCATION GROUP
BY EMPLOYEE_ID,
HOURS_ALLOCATED) ALLOCATED ON ALLOCATED.EMPLOYEE_ID = ACCOUNTING.EMPLOYEE_ID GROUP
BY ACCOUNTING.EMPLOYEE_ID,
EMPLOYEE_NAME,
ALLOCATED.HOURS_ALLOCATED
ORDER
BY EMPLOYEE_NAME ASC
Result from the query above
employee_id
employee_name
hours_allocated
hours_spent
allowance
1
"Annachiara Darius"
12
5.3
18.7
7
"Boro Stanislav"
8
112.5
-88.5
5
"Naevius Matvei"
10
24.8
5.2
2
"Samar Rajani"
16
38.9
9.1
3
"Taonga Eric"
20
6.5
13.5
6
"Theophania Eglantine"
7
7.6
-0.6
4
"Tycho Sigdag"
15
4.5
10.5
As you can see I've managed to get every column displaying the information I wanted correctly.
The problem:
Allowence column is only correct if the employee has only made one entry in the accounting table.
If employee has more than one entry in accounting the calculation is off/wrong.
The line I use to get the allowance is
SUM(ALLOCATED.HOURS_ALLOCATED - ACCOUNTING.HOURS_DONE) AS ALLOWANCE
I've been trying different stuff but can't seem to manage this part of the query.
How can I incorporate this into the group logic?
The answer was posted in a comment.
ALLOCATED.HOURS_ALLOCATED - SUM(ACCOUNTING.HOURS_DONE) is correct
but not
`SUM(ALLOCATED.HOURS_ALLOCATED - ACCOUNTING.HOURS_DONE)` AS ALLOWANCE

SQL Query to find designation of employee

I have 2 tables employee and job_role as below. I need to write a SQL query to find designation of each employee by joining this table.
Input Table
1.Employee
e_id e_name Salary Commission
-------------------------------------
1 ABC 1000 10
2 CDE 2000 4
3 GHI 3500 40
4 JKL 5000 3
5 MNO 1200 25
6 XYZ 3000 2
2.Job_role
Designation Sal_min Sal_max Commission_Min Commission_Max
-----------------------------------------------------------------
Associate 1000 2000 0 5
Lead 2001 3000 6 10
Manager 3001 5000 11 50
Problem: To find designation of each employee based on below logic using SQL Query
Logic:
if sal between 1000 and 2000
AND Commission between 0 and 5 then Associate
if sal between 2001 and 3000
OR Commission between 6 and 10 then Lead
if sal between 3001 and 5000
OR Commission between 11 and 50 then Manager
Desired output:
e_id e_name Salary Commision Designation
----------------------------------------------
1 ABC 1000 10 Lead
2 CDE 2000 4 Associate
3 GHI 3500 40 Manager
4 JKL 5000 3 Manager
5 MNO 1200 25 Manager
6 XYZ 3000 2 Lead
My Attempt:
select e_id,e_name,salary,commision,
case when designation='Associate' And commision between Commission_Min and Commission_Min
then 'Associate'
else designation end designation
from employee e left outer join job_role
on salary between sal_min and sal_max;
Issue: How to check AND condition(commission) only for Associate not for other?
Try This
select e.*,j.Designation from
employee e
left outer join
Job_role j
on (j.Designation="Associate" and
(e.Salary between j.Sal_min and j.Sal_max) and (e.Commission between j.Commission_Min and j.Commission_Max))
or(j.Designation not in("Associate") and
((e.Salary between j.Sal_min and j.Sal_max) or (e.Commission between j.Commission_Min and j.Commission_Max)))
order by e.e_id ;

Selecting from a table that contains ALL of another table

Let's say I have three tables:
Employees:
PID NAME WAGE
---------- -------------------- ----------
10234 Able 8
11567 Baker 9
3289 George 10
88331 Alice 11
Employee_made:
PID SID QUANTITY HOURS
---------- ---------- ---------- ----------
10234 11 24 3
10234 12 6 1
10234 13 24 1
10234 21 6 1
10234 23 4 1
10234 31 48 6
11567 23 4 1
11567 31 1 1
88331 11 6 1
Sandwich:
SID PRICE NAME
---------- ---------- ------------------------------
12 2 hamburger on wheat
13 2 cheese burger
21 1.75 fish burger on rye
23 1.75 fish burger on wheat
31 3 veggie burger on wheat
11 2 hamburger on rye
I need to list all the employees who have made ALL the different sandwiches, and display their names and PID. What I've gotten so far is:
Select E.name, E.pid
From employees E, employee_made EM, sandwich S
Where E.pid = EM.pid
Which tells me the matching PIDs from the employees and employee_made table. Where I'm not sure to go is how to display the employees who have made ALL the sandwiches, so matching not any SID to the employee_made table, but ALL of them.
First, never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You can approach this by counting the number of sandwiches mades by employees and then comparing to the total count of sandwiches:
select em.pid
from employee_made em
group by em.pid
having count(distinct em.sid) = (select count(*) from sandwich);
This gives the pid of the employee. I'll let you figure out how to bring in the employee name (hint: in, exists, and join could all be used).

List the name of employee who workon one project sponsored by his/her division and also work on one project that is not sponsord by his/her division

The code I have for this is
select name
from employee e, workon w
where e.empid = w.empid
and pid in
(select pid
from workon
where did in
(select did
from employee ee
where e.did = ee.did))
group by name
But I know that isn't right, since I also need to find someone who works in a project outside of his division. The problem is that I'm not too sure how to do that.
Tables
Employee
EMPID NAME SALARY DID
1 kevin 32000 2
2 joan 46200 1
3 brian 37000 3
4 larry 82000 5
5 harry 92000 4
6 peter 45000 2
7 peter 68000 3
8 smith 39000 4
9 chen 71000 1
10 kim 46000 5
11 smith 46000 1
Workon
PID EMPID HOURS
3 1 30
2 3 40
5 4 30
6 6 60
4 3 70
2 4 45
5 3 90
3 3 100
6 8 30
4 4 30
5 8 30
6 7 30
6 9 40
5 9 50
4 6 45
2 7 30
2 8 30
2 9 30
1 9 30
1 8 30
1 7 30
1 5 30
1 6 30
2 6 30
Project
PID PNAME BUDGET DID
1 DB development 8000 2
2 network development 6000 2
3 Web development 5000 3
4 Wireless development 5000 1
5 security system 6000 4
6 system development 7000 1
select e.name
from employee e
where
-- Projects in department
exists (
select *
from
workon w
join project p
on w.pid = p.pid
and p.did = e.did
where w.empid = e.empid
)
-- Projects out of department
and exists (
select *
from
workon w
join project p
on w.pid = p.pid
and p.did != e.did
where w.empid = e.empid
)

Retrieve top 48 unique records from database based on a sorted Field

I have database table that I am after some SQL for (Which is defeating me so far!)
Imagine there are 192 Athletic Clubs who all take part in 12 Track Meets per season.
So that is 2304 individual performances per season (for example in the 100Metres)
I would like to find the top 48 (unique) individual performances from the table, these 48 athletes are then going to take part in the end of season World Championships.
So imagine the 2 fastest times are both set by "John Smith", but he can only be entered once in the world champs. So i would then look for the next fastest time not set by "John Smith"... so on and so until I have 48 unique athletes..
hope that makes sense.
thanks in advance if anyone can help
PS
I did have a nice screen shot created that would explain it much better. but as a newish user i cannot post images.
I'll try a copy and paste version instead...
ID AthleteName AthleteID Time
1 Josh Lewis 3 11.99
2 Joe Dundee 4 11.31
3 Mark Danes 5 13.44
4 Josh Lewis 3 13.12
5 John Smith 1 11.12
6 John Smith 1 12.18
7 John Smith 1 11.22
8 Adam Bennett 6 11.33
9 Ronny Bower 7 12.88
10 John Smith 1 13.49
11 Adam Bennett 6 12.55
12 Mark Danes 5 12.12
13 Carl Tompkins 2 13.11
14 Joe Dundee 4 11.28
15 Ronny Bower 7 12.14
16 Carl Tompkin 2 11.88
17 Nigel Downs 8 14.14
18 Nigel Downs 8 12.19
Top 4 unique individual performances
1 John Smith 1 11.12
3 Joe Dundee 4 11.28
5 Adam Bennett 6 11.33
6 Carl Tompkins 2 11.88
Basically something like this:
select top 48 *
from (
select athleteId,min(time) as bestTime
from theRaces
where raceId = '123' -- e.g., 123=100 meters
group by athleteId
) x
order by bestTime
try this --
select x.ID, x.AthleteName , x.AthleteID , x.Time
(
select rownum tr_count,v.AthleteID AthleteID, v.AthleteName AthleteName, v.Time Time,v.id id
from
(
select
tr1.AthleteName AthleteName, tr1.Time time,min(tr1.id) id, tr1.AthleteID AthleteID
from theRaces tr1
where time =
(select min(time) from theRaces tr2 where tr2.athleteId = tr1.athleteId)
group by tr1.AthleteName, tr1.AthleteID, tr1.Time
having tr1.Time = ( select min(tr2.time) from theRaces tr2 where tr1.AthleteID =tr2.AthleteID)
order by tr1.time
) v
) x
where x.tr_count < 48