Select max date from joined tables with columns that has unique values - sql

I want to get the most recent date from joined tables with unique values in 2 columns. How do I do this? I have also tried the ranking (but John has the same rank) and tried rownum = 1, but I still get the same results below for some reason
Name ID Email DeptNo DeptScore OnDate
John A46 john#doe.com 100 50 5/11/2011
John A46 johndoe#aol.com 200 75 7/21/2015
Alice B33 alice#hotmail.com 100 50 4/15/2014
I want to get the following:
Name ID Email DeptNo DeptScore OnDate
John A46 johndoe#aol.com 200 75 7/21/2015
Alice B33 alice#hotmail.com 100 50 4/15/2014
My query
select distinct e.name, e.id, e.email, d.deptno, d.deptscore, d.ondate
from
emp e
inner join dept d on
d.deptno = e.dnum
and d.ondate = e.livedate
and d.ondate = (select max(m.ondate)
from dept m
where d.ondate = m.ondate)
--where e.id in ('A46','B33')

Try to use the below Query, it will solve your problem.
select name,
id,
email,
deptno,
deptscore,
ondate
from (select e.name,
e.id,
e.email,
d.deptno,
d.deptscore,
d.ondate,
rank() over(partition by e.id,e.name order by d.ondate desc) rn
from emp e join
dept d
on d.deptno = e.dnum and d.ondate = e.livedate
) s
where rn = 1;
Output:
NAME ID EMAIL DEPTNO DEPTSCORE ONDATE
John A46 johndoe#aol.com 200 75 21-JUL-15
Alice B33 alice#hotmail.com 100 50 15-APR-14

Related

Unable to MAX(COUNT) and have multiple columns

I have 4 tables, EMPLOYEE, DRIVER, TRIP and TRIPLEG
EMPLOYEE table has Name which I want to extract and show with MAX count, has E# which is shared with DRIVER
DRIVER table has L#(licence number) which is common with TRIP
TRIP table has T#(trip number) which is common with TRIPLEG
I'm trying to find the max number of tripleg a driver has done(In this case driver with licence number 10002:
SELECT MAX(COUNT(TRIPLEG.LEG#))
FROM TRIP, TRIPLEG
ON TRIP.T# = TRIPLEG.T#
WHERE TRIP.L# = 10002
GROUP BY TRIP.T#
COUNT(TRIPLEG.LEG#) gives me https://i.imgur.com/AYAovov.png,
so I did the above MAX(COUNT(TRIPLEG.LEG#)) which gives me this: https://i.imgur.com/alCFlO3.png
I'm unable to proceed as I tried SELECTING more columns(TRIP.T#) like
SELECT TRIP.T#, MAX(COUNT(TRIPLEG.LEG#))
FROM TRIP, TRIPLEG
ON TRIP.T# = TRIPLEG.T#
WHERE TRIP.L# = 10002
GROUP BY TRIP.T#
Gives me an error: ORA-00937: not a single-group group function
Any advice? Need to be able to start small and selecting before I can join more tables to get the Employee name displayed beside the MAX tripleg count
Thanks in advance
Essentially I want something like: (only 1 row, which is the MAX triplegs done (5))
NAME MAX(COUNT(TRIPLEG.LEG#))
-----------------------------------
BOB 5
I don't have your table so I'll use Scott's EMP and DEPT (as you use Oracle, so I presume you're familiar with them).
This works:
SQL> select d.dname, count(e.empno) cnt
2 from emp e join dept d on e.deptno = d.deptno
3 where d.deptno in (10, 20)
4 group by d.dname;
DNAME CNT
-------------- ----------
ACCOUNTING 3
RESEARCH 5 --> MAX count is this
SQL>
Nested count works if there are no other columns in SELECT column list (you already know that), and it returns desired value:
SQL> select max(count(e.empno)) cnt
2 from emp e join dept d on e.deptno = d.deptno
3 where d.deptno in (10, 20)
4 group by d.dname;
CNT
----------
5
SQL>
But, this won't work (you know that too):
select d.dname, max(count(e.empno)) cnt
from emp e join dept d on e.deptno = d.deptno
where d.deptno in (10, 20)
group by d.dname;
To fix it, use CTE (Common Table Expression a.k.a. the WITH factoring clause) or an inline view; I'll show you the first option, with yet another addition: I'll rank counts and find the "highest" one, and use it later to select only desired row.
SQL> with tcnt as
2 (select d.deptno,
3 d.dname,
4 count(e.empno) cnt,
5 rank() over (order by count(e.empno) desc) rnk --> rank them DESC
6 from emp e join dept d on e.deptno = d.deptno
7 where d.deptno in (10, 20)
8 group by d.dname, d.deptno
9 )
10 select t.deptno, t.dname, t.cnt
11 from tcnt t
12 where rnk = 1; --> fetch only row(s) with highest rank
DEPTNO DNAME CNT
---------- -------------- ----------
20 RESEARCH 5
SQL>
Finally, add some more columns from other tables:
SQL> with tcnt as
2 (select d.deptno,
3 d.dname,
4 count(e.empno) cnt,
5 rank() over (order by count(e.empno) desc) rnk
6 from emp e join dept d on e.deptno = d.deptno
7 where d.deptno in (10, 20)
8 group by d.dname, d.deptno
9 )
10 select t.deptno, t.dname, t.cnt, e.ename, e.job
11 from tcnt t join emp e on e.deptno = t.deptno
12 where rnk = 1;
DEPTNO DNAME CNT ENAME JOB
---------- -------------- ---------- ---------- ---------
20 RESEARCH 5 SMITH CLERK
20 RESEARCH 5 JONES MANAGER
20 RESEARCH 5 SCOTT ANALYST
20 RESEARCH 5 ADAMS CLERK
20 RESEARCH 5 FORD ANALYST
SQL>
Based on your tables to find the max number of tripleg a driver has done(In this case driver with licence number 10002:
Select a.tripno, max(a.trips)
From
(Select Trip.T# as tripno, count(tripleg.leg#) as trips
From tripleg join trip on tripleg.T# = trip.T#
where trip.L# = 10002
Group by tripno
) a
Group by a.tripno

how to find the maximum salary of employees in a specific department

I have a table named SalaryTable containing salaries of employee in various departments:
dept_id name salary
12 a 100
13 b 200
12 c 300
14 d 400
12 e 500
13 f 600
I need to find the maximum salary of each department with given department id AND the name of that person along with maximum salary.
I am using the following sql query for this
select dept_id, name, max(salary)
from SalaryTable
group by salary
But the above code is giving me error:
dept_id must be an aggregate expression or appear in GROUP BY clause
I am able to get the following table easily with this below query:
select dept_id, max(salary) as max_salary
from SalaryTable
group by salary
dept_id max_salary
12 500
13 600
14 400
but I also need the name of that person as:
REQUIRED OUTPUT
dept_id name max_salary
12 e 500
13 f 600
14 d 400
You appear to be learning SQL, so you can build on what you have. The following gets the maximum salary:
select dept_id, max(salary)
from SalaryTable
group by dept_id;
You can use this as a subquery, to get all matching names:
select st.*
from SalaryTable st join
(select dept_id, max(salary) as max_salary
from SalaryTable
group by dept_id
) std
on st.dept_id = std.dept_id and
st.salary = std.max_salary
use correlated subquery
select dept_id, name, salary
from SalaryTable a
where salary =(select max(salary) from SalaryTable b where a.dept_id=b.dept_id)
To be exact:
SELECT dept_id, NAME, salary FROM SalaryTable a
WHERE salary =(SELECT MAX(salary) FROM SalaryTable b WHERE a.dept_id=b.dept_id)
ORDER BY dept_id;
Also see try by joins because see this
Remember: Whatever you put in between select and from in single sql statement that must be used in the group by clause (That's what your error says!).
You can do it with NOT EXISTS:
select s.* from SalaryTable s
where not exists (
select 1 from SalaryTable
where dept_id = s.dept_id and salary > s.salary
)
order by s.dept_id
See the demo.
Results:
> dept_id | name | salary
> ------: | :--- | -----:
> 12 | e | 500
> 13 | f | 600
> 14 | d | 400

SQL Query to Retrieve the details of those employees who works in a department having head count more than 5

I have the following Table.
STAFF
STAFFNO STAFFNAME DESIGNATI SALARY DEPTNO
---------- ---------- --------- ---------- ----------
1000 Rajesh Manager 35000 1
1001 Manoj Caretaker 7420.35 1
1002 Swati HR 22500 3
1003 Suresh HR 23400 3
1004 Najim Mangager 17200 2
1006 Ritesh Prgrmr 23500 2
1005 Nisha Prgrmr 24852 1
1007 Rajib Security 6547 3
1008 Neeraj Prgrmr 17300 1
1009 Dushant Prgrmr 16500 1
1010 Pradyut Manager 26300 2
1011 Manisha Prgrmr 21500 2
1012 Janak Security 8500 2
Now I want to run a query on oracle (SQL*Plus) in which I can retrieve the details of those employees who works in a department having 5 or more head count.(e.g. deptno. 1 and deptno. 2 have 5 employees working in them)
Can you help me with the Oracle query to retrieve that? Thanks in advance.
You need create a sub query or perform a JOIN.
With a JOIN first you need to know what department has more that 5 employees.
SELECT DEPTNO
FROM STAFF
GROUP BY DEPTNO
HAVING COUNT(*) >= 5
Now you join both result
SELECT S.*
FROM STAFF S
JOIN ( SELECT DEPTNO
FROM STAFF
GROUP BY DEPTNO
HAVING COUNT(*) >= 5 ) F
ON S.DEPTNO = F.DEPTNO
Subquery version:
SELECT S.*
FROM STAFF S
WHERE S.DEPTNO IN ( SELECT DEPTNO
FROM STAFF
GROUP BY DEPTNO
HAVING COUNT(*) >= 5 )
If you want the employee detail, then you actually want an analytic function:
select s.*
from (select s.*, count(*) over (partition by deptno) as deptcnt
from staff
) s
where deptcnt >= 5;
It should be like this
SELECT * FROM STAFF WHERE DEPTNO IN
(SELECT DEPTNO FROM STAFF GROUP BY DEPTNO HAVING COUNT(*)>4)
Here it is using a join (because no one has) it may allow you to change your BI rules easier....
SELECT S.*
FROM STAFF S
LEFT JOIN (
SELECT DEPTNO, COUNT(*) AS C
FROM STAFF
GROUP BY DEPTNO
) AS D_COUNTS ON S.DEPTNO = D_COUNT.DEPTNO
WHERE D_COUNTS.C >= 5
or as a CTE
WITH D_COUNTS AS
(
SELECT DEPTNO, COUNT(*) AS C
FROM STAFF
GROUP BY DEPTNO
)
SELECT S.*
FROM STAFF S
LEFT JOIN D_COUNTS ON S.DEPTNO = D_COUNT.DEPTNO
WHERE D_COUNTS.C >= 5

Retrieving MAX(date) value from joined table

I need help on a very basic SQL join concept, that I just can't seem to get right.
I have an employee table and a position table. The employee table is like so:
EmpID Name
1 Jane Jones
2 Bob Smith
3 Jim Adams
The position table is like this:
PosID EmpID Position DateFilled
1 1 Sales 1/2/2012
2 2 HR 4/5/2013
3 2 Mgmnt 6/1/2014
4 2 Sr. Mgmnt 7/5/2015
5 3 IT Support 4/6/2014
6 3 IT Devel. 5/11/2015
How can I get the following output:
EmpID Name Position DateFilled
1 Jane Jones Sales 1/2/2012
2 Bob Smith Sr. Mgmnt 7/5/2015
3 Jim Adams IT Devel. 5/11/2015
So, in other words, how do I join to get only the record with the max DateFilled column from the position table to join with the corresponding record in the employee table?
Any assistance would be greatly appreciated.
You can use ROW_NUMBER:
SELECT e.EmpID, e.Name, p.Position, p.DateFilled
FROM employee e
LEFT JOIN (
SELECT EmpID, Position, DateFilled,
ROW_NUMBER() OVER (PARTITION BY EmpID
ORDER BY DateFilled DESC) AS rn
FROM position
) p ON e.EmpID = p.EmpID AND p.rn = 1
You can do it using MAX() KEEP ( DENSE_RANK [FIRST|LAST] ... ) like this:
SELECT e.EmpId,
e.Name,
p.position,
p.datefilled
FROM employee e
INNER JOIN (
SELECT EmpID,
MAX( Position ) KEEP ( DENSE_RANK LAST ORDER BY DateFilled ) AS Position,
MAX( DateFilled ) AS DateFilled
FROM position
GROUP BY EmpID
) p
ON ( e.EmpId = p.EmpID );
try this
select temp.EmpID,(select position from Position where PosID =temp.PosID) position,DateFilled,Name from
(select EmpID,max(PosID) PosID,max(DateFilled) DateFilled
from position group by EmpID ) temp
inner join employee emp on emp.EmpID =temp.EmpID

select dept names who have more than 2 employees whose salary is greater than 1000

How would do the following in SQL
"select dept names who have more than 2 employees whose salary is greater than 1000" ?
DeptId DeptName
------ --------
1 one
2 two
3 three
EmpId DeptId Salary
----- ------ ------
121 1 2000
122 1 2000
123 1 5000
124 1 4000
131 2 2000
132 2 6000
133 2 1000
134 2 1000
125 3 1000
126 3 20000
RESULT: one
How about something like this?
SELECT D.DeptName FROM
Department D WHERE (SELECT COUNT(*)
FROM Employee E
WHERE E.DeptID = D.DeptID AND
E.Salary > 1000) > 2
SELECT DEPTNAME
FROM(SELECT D.DEPTNAME,COUNT(EMPID) AS TOTEMP
FROM DEPT AS D,EMPLOYEE AS E
WHERE D.DEPTID=E.DEPTID AND SALARY>1000
GROUP BY D.DEPTID
)
WHERE TOTEMP>2;
select min(DEPARTMENT.DeptName) as deptname
from DEPARTMENT
inner join employee on
DEPARTMENT.DeptId = employee.DeptId
where Salary > 1000
group by (EmpId) having count(EmpId) > =2
hope this helps
select DeptName from DEPARTMENT inner join EMPLOYEE using (DeptId) where Salary>1000 group by DeptName having count(*)>2
select D.DeptName from [Department] D where D.DeptID in
(
select E.DeptId from [Employee] E
where E.Salary > 1000
group by E.DeptId
having count(*) > 2
)
select deptname from dept_1
where exists
(
SELECT DeptId,COUNT(*)
FROM emp_1
where salary>1000
and emp_1.deptid=dept_1.deptid
GROUP BY DeptId
having count(*)>2)
1:list name of all employee who earn more than RS.100000 in a year.
2:give the name of employee who earn heads the department where employee with employee I.D
My main advice would be to steer clear of the HAVING clause (see below):
WITH HighEarners AS
( SELECT EmpId, DeptId
FROM EMPLOYEE
WHERE Salary > 1000 ),
DeptmentHighEarnerTallies AS
( SELECT DeptId, COUNT(*) AS HighEarnerTally
FROM HighEarners
GROUP
BY DeptId )
SELECT DeptName
FROM DEPARTMENT NATURAL JOIN DeptmentHighEarnerTallies
WHERE HighEarnerTally > 2;
The very early SQL implementations lacked derived tables and HAVING was a workaround for one of its most obvious drawbacks (how to select on the result of a set function from the SELECT clause). Once derived tables had become a thing, the need for HAVING went away. Sadly, HAVING itself didn't go away (and never will) because nothing is ever removed from standard SQL. There is no need to learn HAVING and I encourage fledgling coders to avoid using this historical hangover.