SQL query with correlated subquery in where clause - sql

I am fighting with a SQL.
The task is to write max(EMP.SAL) for each project (PROJ_EMP.PROJNO)
I have 3 tables.
Table PROJ which keep data about projects:
PROJ.PROJNO | PROJ.NAME
------------+-------------
1 | PROJECT1
2 | PROJECT2
3 | PROJECT3
Table EMP for employees data:
EMP.EMPNO | EMP.NAME | EMP.SALARY
----------+----------+------------
1000 | name1 | 4000
1001 | name2 | 2000
1002 | name3 | 3000
1003 | name4 | 6000
1004 | name5 | 1000
And Table PROJ_EMP for connecting these projects with employees:
PROJ_EMP.EMPNO | PROJ_EMP.PROJNO
---------------+----------------
1000 | 1
1001 | 1
1002 | 2
1003 | 2
1004 | 3
Such I mentioned at the beginning post: I am trying to write max(EMP.SAL)for each project using a correlated subquery in where clause so the desired result should be:
PROJ_EMP.PROJNO | EMP.EMPNO | EMP.SAL
----------------+-----------+---------
1 | 1000 | 4000
2 | 1003 | 6000
3 | 1004 | 1000
I don't have any working result however my SQL query closed to aim looks:
SELECT EMP.EMPNO, EMP.SAL, PROJ_EMP.PROJNO
FROM EMP, PROJ_EMP
WHERE EMP.EMPNO = PROJ_EMP.EMPNO
AND EMP.SAL = (SELECT MAX(EMP.SAL)
FROM EMP, PROJ_EMP p_e
WHERE EMP.EMPNO = PROJ_EMP.EMPNO
AND PROJ_EMP.PROJNO = p_e.PROJNO)
GROUP BY
PROJ_EMP.PROJNO, EMP.SAL, EMP.EMPNO
ORDER BY
PROJ_EMP.PROJNO, EMP.SAL DESC
By the result are not like I expected. Can you help me? Thank you fo any help in advance

Learn to use proper, explicit, standard JOIN syntax. I think you are trying to write:
SELECT e.EMPNO, e.SAL, pe.PROJNO
FROM EMP e JOIN
PROJ_EMP pe
ON e.EMPNO = pe.EMPNO
WHERE EMP.SAL = (SELECT MAX(EMP.SAL)
FROM EMP e2 JOIN
PROJ_EMP pe2
ON e2.EMPNO = pe2.EMPNO
WHERE pe2.PROJNO = pe.PROJNO
)
ORDER BY pe.PROJNO, e.SAL DESC ;

You can apply inner join among three tables and filter by max analytic function partitioned by project number and ordered by descending salary to determine the max salaries for each project number :
select projno, empno, salary
from
(
select p.projno, e.empno, e.salary,
max(e.salary) over (partition by p.projno order by e.salary desc) as max_salary
from proj p
join proj_emp pe on pe.projno = p.projno
join emp e on e.empno = pe.empno
)
where salary = max_salary;
Demo

Related

Update only rows that does not match rows from another table

I have 3 tables:
1) tblPerson
id pin name dept_id
---|-----------|------------|------------|
1 | 123 | Lisa | 100 |
2 | 234 | Rob | 200 |
2) tblDepartment
id dept_name
-----|-----------|
100 | IT |
200 | HR |
3) tblMaster
id emplid name m_dept
---|-----------|------------|------------|
1 | 123 | Lisa | IT |
2 | 234 | Rob | HR |
• tblDepartment gets its rows from existing departments present in tblMaster
• in tblPerson, dept_id is a foreign key from tblDepartment
I am trying to create a query that will update the dept_id in tblPerson for all rows where the m_dept does not match the dept_name of the dept_id linked to a person.
So for example, if in tblMaster, I change 'IT' under m_dept from row 1 to 'HR', running the query will change the dept_id of row 1 in tblPerson to '200'
SQL Query:
UPDATE [dbo].[tblPerson]
SET dept_id = d.id
FROM [dbo].[tblMaster] m
INNER JOIN [dbo].[tblPerson] p
ON p.pin = m.emplid
INNER JOIN [dbo].[tblDepartment] d
ON d.dept = m.m_dept
the query above will update all rows..when i try to add:
WHERE d.dept != m.m_dept
and I change the m_dept 'IT' to 'HR' of row 1 in tblMaster ..it does not update anything
need help please ;m;
You are currently using both d.dept = m.m_dept (in the JOIN condition) and d.dept != m.m_dept in the WHERE, so of course you are updating no rows.
You either use a EXISTS or NOT EXISTS, or another JOIN:
UPDATE P
SET P.dept_id = D1.id
FROM dbo.tblPerson P
INNER JOIN dbo.tblMaster M
ON P.pin = M.emplid
INNER JOIN dbo.tblDepartment D1
ON D1.dept_name = M.m_dept
INNER JOIN dbo.tblDepartment D2
ON P.dept_id = D2.id
WHERE D1.dept_name <> D2.dept_name
;

Kindly help to write SQL queries

I need your help to write two SQL queries (DB Oracle) to fetch data. Both table has huge data so need to take care of the performance also. Below is the scenario -
There are two tables Department (DEPT) and Employee (EMP). They have a 1 (DEPT) : M (EMP) relationship.
Department table has columns
Row_id, DeptNm, Created_date
Employee table has columns
Row_id, EMPName, Emp_num, Par_row_id (FK to DEPT.row_Id), Salary
For a specific Department, sort data per employee's decreasing salary and rank it. Data should be shown like this:
DeptNm | EmpNm | Salary | Rank
--------------------------------
Finance | Vikram | 200000 | 1
Finance | Uttaam | 150000 | 2
Finance | Rajeev | 100000 | 3
ITDPPT | Balaajii | 150000 | 1
ITDEPT | Harsha | 120000 | 2
ITDEPT | Weeniji | 100000 | 3
Query that to show the data highest salary for a department. Data should be as -
Dept_Nm | EMP_NM | Salary
Finance | Vikramadit | 2000000
ITDEPT | Balaji | 1500000
select *
from (
select dp.deptname,
emp.empname,
emp.salary,
dense_rank() over (partition by dp.deptname order by emp.salary desc) as rnk
from employee emp
join department dp on dp.row_id = emp.par_row_id
) t
where rnk = 1
Try this will help you please put Rank as I didn't get what process you want if you want dynamic Rank than try any "temp" variable.
select D.DeptName,E.EmpName,E.Salary from Employee E
lefe join Department as D on D.Par_Row_Id=E.Row_Id order by E.Salaray DESC
select D.DeptName,E.EmpName,E.Salary from Employee E
left join Department as D on D.Par_Row_Id=E.Row_Id order by E.Salaray DESC

Return name of the employee who having top salary with join

here is the situation. I have two tables, one is table Tbl_employ, second is tbl_details.
Tbl_employ
----------
id | name
1 | Ravi
2 | ram
3 | sham
4 | john
Tbl_details
-----------
id | salary | emp_id
1 | 500 | 1
2 | 200 | 2
3 | 400 | 3
4 | 501 | 4
I want to return the name of the employee who has top salary in tbl_detail.
What will be the join query for this condition?
Please suggest. Thanks in advance.
Perhaps:
SELECT TOP(1) name
FROM Tbl_employ e INNER JOIN Tbl_details d ON e.id = d.emp_id
ORDER BY d.salary DESC;
Essentially, this joins the two tables on the key fields (id and emp_id), returning only a single result (TOP(1)) that is the maximum salary row (ORDER BY d.salary DESC).
I appreciate the answer of #Max Vernon.
You can also do it by another way. Please try this
select t.name from (
select Distinct top 1 salary ,name
from Tbl_employ as E
left outer join Tbl_details as D on D.empid=E.id
order by salary desc
) as t
you can check it here SQL Fiddle

Oracle Query design

I have two tables joining with left outer join
Employee
Employeed_Id Employee_Name Location_id
1 David 1
2 Andrew 2
3 Mike 3
4 steve 4
Employee_profile
profile_id profile_name location_id profile_location
1 manager 1 NYC
2 accountant 2 Jersey
3 engineer 1 Mexico
4 trainer 3 Boston
This is the common query I have to retrieve the all employees based on location.here profile_location is unique.
Problem is, in some part of the application profile_location is not required. So Outer join between above tables is not required.
How to develop a query, so it should function normally in case of profile_location not have input value with outer join.
Below is my Query:
select e.Employee_Name
from Employee e,
Employee_profile ep
where e.location_id (+) = ep.location_id
and ep.profile_location='xxxxx'
If you want to return those records that match your passed in profile_location but also want to return all records when the location does not exist, then you can use something like this:
select distinct e."Employee_Name"
from Employee e
left join Employee_profile ep
on e."Location_id" = ep."location_id"
where ep."profile_location" = 'xxx'
or not exists (select ep1."profile_location"
from Employee_profile ep1
where ep1."profile_location" = 'xxx')
See SQL Fiddle with Demo
If you pass in a value that does not exist like 'xxx' the result is:
| EMPLOYEE_NAME |
-----------------
| David |
| Andrew |
| steve |
| Mike |
If you pass in 'NYC' the result is:
| EMPLOYEE_NAME |
-----------------
| David |
select e.Employee_Name
from Employee e,
Employee_profile ep
where e.location_id (+) = ep.location_id
and (ep.profile_location='xxxxx'
Or ep.profile_location is null)

Guide me with this stored procedure or function

Manager | Employee |HireDate
----------------------------------------
ManagerA| EmpA |1/1/2012
managerA| EmpB |1/15/2012
ManagerB| Emp C |2/1/2012
ManagerA| Emp D |2/15/2012
ManagerB| Emp E |2/8/2012
The bonus amount for each manager is calculated based on how many recruits were hired that month.
ex. each Manager gets 1000 for first hire and 500 additional for every next.
Its almost like each record has a seed
Manager | Employee |HireDate | Seed
------------------------------------------------
ManagerA| EmpA |1/1/2012 | 1
managerA| EmpB |1/15/2012 | 2
ManagerB| Emp C |2/1/2012 | 1
ManagerA| Emp D |2/15/2012 | 1
ManagerB| Emp E |2/8/2012 | 2
and Bonus is a function of the seed as 1000+(seed-1)*500
I need help generating the seed .I am not sure if I should use a stored procedure to generate the seed or a function
eventually I want to generate a table as below
Manager | Employee |HireDate | Bonus
-------------------------------------------------
ManagerA| EmpA |1/1/2012 | 1000
managerA| EmpB |1/15/2012 | 1500
ManagerB| Emp C |2/1/2012 | 1000
ManagerA| Emp D |2/15/2012 | 1000
ManagerB| Emp E |2/8/2012 | 1500
To get the seed
Select
*
,ROW_NUMBER() Over(Partition By Manager, Year(HireDate), Month(HireDate) Order By HireDate) As Seed
From
YourTable
To get the bonus directly
Select
*
,1000 + (Seed - 1) * 500 As Bonus
From
(
Select
*
,ROW_NUMBER() Over(Partition By Manager, Year(HireDate), Month(HireDate) Order By HireDate) As Seed
From
YourTable
) T