SQL Group by, but allow duplicate if value is the same - sql

I'm trying to group some max values by an ID (until here i got it figured out), and I also need to select the names from the persons with the max values, so my grouping should allow duplicates if two persons with that grouped ID have the same value (max).
Here's what I've got so far.
SELECT MGR,MAX(SAL) AS MaxSal
FROM EMP
WHERE MGR IS NOT NULL
GROUP BY MGR
Now I also need to extract the field ENAME, how could I do this, while grouping and also allowing duplicate groups when necessary ?

Starting Oracle 12c, one option uses window functions in the order by clause and a fetch clause:
select mgr, ename, sal
from emp
where mgr is not null
order by rank() over(partition by mgr order by sal desc)
fetch first row with ties

The solution is analytic functions. Here's how I achieved my desired result.
SELECT MGR,ENAME,SAL
FROM
(
SELECT MGR,ENAME,SAL,
MAX(SAL) OVER (PARTITION BY MGR) AS MaxSal
FROM EMP
)
WHERE SAL=MaxSal

Related

from keyword error in oracle apex site

I have tried checking all the duplicate answers provided in this site but couldn't able to come up with rectifying my error could you guys help me out on this?
Getting this error
ORA-00923: FROM keyword not found where expected
SELECT TOP 1 sal FROM emp WHERE sal in
(SELECT DISTINCT TOP 3 sal FROM emp ORDER BY sal DESC)
ORDER BY sal ASC;
I am solving this using oracle apex site
You appear to want to find thew record with the third-lowest salary.
You can use a subquery to assign an analytic rank to each salary, and then filter on that:
select * from (
select e.*, dense_rank() over (order by sal desc) as rnk
from emp e
)
where rnk = 3;
From 12c you can use the offset and fetch syntax to do the same thing:
select * from emp
order by sal desc
offset 3 rows
fetch first row only;
You need to decide how to deal with ties though - if more than one employee shares that third-lowest salary; or even if the lowest and second lowest are awarded to more than one person. Depending on what you want to happen you can look at variations of the 12c row-limiting syntax, and other analytic functions - row_number(), dense_rank() - and their windowing options.
I was able to get my query now
SELECT A.* FROM emp A where 3 =(SELECT COUNT(DISTINCT sal) FROM emp B WHERE A.sal <= B.sal);
Yet another option, using analytic function:
WITH ranks
AS (SELECT empno, DENSE_RANK () OVER (ORDER BY sal DESC) rnk FROM emp)
SELECT e.*
FROM emp e, ranks r
WHERE e.empno = r.empno
AND r.rnk = 3;

can't we use select another column with max() in sql

I have a table emp (ename,eid,did,sal,sex) where column did is foreign key with another table dept (did,dname).
I want to get the max sal of the company along with name and did of the person who is getting it.
I am executing following query
select did,ename ,max(sal) from emp;
But the Result is :
ORA-00937: not a single-group group function
so My question is can't I have more than 1 columns ?
You can't use MAX aggregate function like this. Using MAX without a GROUP BY clause will just return one record with the maximum sal value. You are not allowed to place any more non-aggregated fields in the SELECT clause.
If you want to get the record having the maximum sal value, then you have to do a self-join:
select e1.*
from emp as e1
inner join (
select max(sal) as max_sal
from emp
) as e2 on e1.sal = e2.max_sal
Note: The above query will return more than one records from table emp, in case more than one records share the same maximum sal value.
Edit:
If you want to get the maximum salary per department then you have to include a GROUP BY clause in the derived table used:
select e1.*
from emp as e1
inner join (
select did, max(sal) as max_sal
from emp
group by did
) as e2 on e1.did = e2.did and e1.sal = e2.max_sal
You would have to group the results by the sal column:
select did,ename,max(sal) from emp group by sal
MAX operates over the group specified in a GROUP BY clause and finds the maximum value for each group. When not specifying a set of columns to group by, it finds the max for the entire results set.
You need to find the max sal, then you can query the rows that match:
select did, ename, sal
from emp
where sal = (select max(sal) from emp)

Display columns based on sub query

I want to display the name of department with highest SUM of salary.
I am using oracle sql and the table structure is Dept(Deptno,Dname,Loc) and Emp(Empno,Ename,Job,Salary,Deptno).
The query I use was
select Dname
from Dept
where Deptno=
( select Deptno
from Emp
where rownum=1
group by Deptno
order by sum(Salary) Desc
);
This gives an error:
Right parenthesis missing.
When I run the sub-query alone, it successfully returns a Deptno. But with the parent query, I get the above error.
What is the problem and what can be the possible solution?
select dname
from (select dname, rank() over (order by sum(salary) desc) rnk
from dept d
inner join emp e
on e.deptno = d.deptno
group by dname, e.deptno
)
where rnk = 1;
note, in your example putting where rownum=1 where you did is a huge bug. it would mean pick 1 random row and sort it (not really the highest salary row..just any old row)
my solution may get over 1 row if 2 deptartments have the same highest salary. you can use row_number() instead of rank() to just pick one if you want.

sort query result without selecting that column but sort by that column?

I have a query, I have to sort the result from the DB2 database. The query will select the columns empname,salary,status. But I have to sort the result using order by empno
But the query is not working.. This is the query.
select empname, salary, status from emp where salary>5000 order by empno
Can you update the query to sort by empno without using it in selecting columns?
Your syntax seems correct to me except dot(.) at the end. After removing dot if doesn't work...
Try something like
SELECT empname, salary, status
FROM (SELECT *
FROM emp
ORDER BY empno)
WHERE salary > 5000
Another syntax that may be easier, depending on how you think about it is using the with keyword. This explicitly creates a named temporary table with the desired ordering, then queries from that. The order of the new query will be the same as the temporary tables ordering.
WITH temp_table AS (SELECT *
FROM emp
ORDER BY empno)
SELECT empname, salary, status
FROM temp_table
WHERE salary > 5000;
The answer by #jaychapani is more concise and functionally does the same thing, but the with syntax is powerful for quite a few other use cases and visually separates the two, which can be helpful especially if you have a long subquery that does other things.
I used below query to solve this problem.
In this case we can sort query result without displaying the column:
WITH temp_table
AS (select distinct(s1.Name),s1.id
from students s1
where marks>75
order by right(s1.Name ,3) asc,s1.id asc
)
SELECT Name
FROM temp_table;
I'm not sure, but the fastest way on DB is something like this:
SELECT empname, salary, status
FROM (
select empname, salary, status, empno
from emp
where salary > 5000
order by empno ASC
)
try this
select empname, salary, status from emp where salary>5000 order by empno asc
make sure that columns and table name really exist.
have a look at: ORDER BY clause
Best Regards

dense_rank() analytic function in oracle

SELECT empno, deptno
dense_rank() OVER (PARTITION BY deptno
ORDER BY sal NULLS LAST) SRLNO
FROM emp
WHERE deptno IN (10, 20)
group by empno, deptno --,sal
ORDER BY deptno, SRLNO;
This Query didn't work because Sal should be in group by clause. Can anyone explain why it is so, and is there any alternative to get the rank in the same select without changing the group by clause? U want to order rank only based on salary.
EDIT
Suppose there is another column name commision in emp table and i have to group by deptno and commision and partition by deptno only ,So what will be the suggested answer :
SELECT empno, deptno,sum(sal)
dense_rank() OVER (PARTITION BY deptno
ORDER BY sal NULLS LAST) SRLNO
FROM emp
WHERE deptno IN (10, 20)
group by deptno,commision --,sal
ORDER BY deptno, SRLNO;
now how can i group by depno and commision and only partition by deptno.
HOW CAN I GROUP BY ON DIFFERENT COLUMN AND FIND RANK BASED ON PARTITION BY ON DIFFERNT COLUMN
Don't group by anything--your partition by does it for you!
More specifically, since you're referencing sal in your partition by and order by, group by needs to be aware of it to group the results bu that. However, in this case, you don't need the group by because your dense_rank is using its own partitioning from the partition by clause, and will not follow whatever is in group by.
Regarding your edit, use your over clause there:
sum(sal) over (partition by deptno, commission) as salsum