Display the name of the maximum salary holder (WITHOUT USING A SUBQUERY) - sql

Say there's a table
Name Salary
Joe 4000
Steve 6000
I could just do this
select name from emp where salary = (select max(salary) from emp);
but is there a way to do this without using a subquery?? Please help.
EDIT: Sorry I forgot to mention that I'm using Oracle 10g and LIMIT doesn't work on it

You didn't mention the version of Oracle.
On Oracle 12 there is a new low limiting clause that can be used:
SELECT name
FROM emp
ORDER BY salary desc
FETCH FIRST 1 ROWS ONLY;
There are examples in documentation: https://docs.oracle.com/database/121/SQLRF/statements_10002.htm#BABEAACC
On earlier versions it can't be done without using a subquery, but if you must then create a view:
CREATE VIEW emp_ordered AS
SELECT *
FROM emp
ORDER BY salary desc;
and then query this view in this way:
SELECT * FROM emp_ordered
WHERE rownum <=1

ANSI SQL answer (no dbms specified):
select Name, Salary
from emp
order by Salary desc
fetch first 1 row only
Edit: Will work with newer Oracle versions.

In Oracle 12c, the top-n row limiting feature is introduced. Which allows to ORDER the rows without an additional subquery. So, no more dependency on ROWNUM and explicit sorting in a subquery.
For example,
SQL> SELECT ename, sal FROM emp ORDER BY sal DESC
2 FETCH FIRST 1 row only;
ENAME SAL
---------- ----------
KING 5000
SQL>
Update Regarding duplicate rows
There is an option WITH TIES which will include the duplicate rows.
For example,
SQL> insert into emp(empno, ename, sal) values(1234, 'LALIT', 5000);
1 row created.
SQL> SELECT ename, sal FROM emp ORDER BY sal DESC FETCH FIRST 1 ROWS WITH TIES;
ENAME SAL
---------- ----------
KING 5000
LALIT 5000
SQL>

Try this
SELECT name FROM emp
ORDER BY salary DESC
LIMIT 1

Try
select * from emp order by salary DESC limit 1

Related

select sal from emp order by sal desc limit 1,1;

select sal from emp order by sal desc limit 1,1;
SQL command not properly ended GIVES ERROR
I wan´t to get the employee with the NTH highest salary in each department.
I´m using SQL.
You can use the ANSI syntax offset ... fetch ...:
select sal from emp order by sal desc offset 1 rows fetch next 1 rows only;
I hope you find it useful Link
but you will need group by if you need it by section
select
department,
max(sal)
from emp
group by department

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

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

Trouble when joining two queries Oracle SQL

I have a table on employees like this:
ENAME JOB
Jack Clerk
Adam Manager
Raphael President
And my idea is to get the names that have the maximum length and the minimum length (1 per each) and in case the length is the same, take the one that goes first alphabetically (for example in the case of Jack and Adam, both with 4 characters, it would take Adam):
ENAME LENGTH
Adam 4
Raphael 7
I couldn't find the way of doing it in one unique query so I tried to join two queries but it keeps giving me error ('ORA-00933: SQL command not properly ended') and I don't know why:
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MAX(LENGTH(ENAME)) FROM emp)
ORDER BY ENAME
FETCH FIRST 1 ROW ONLY
union all
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MIN(LENGTH(ENAME)) FROM emp)
ORDER BY ENAME
FETCH FIRST 1 ROW ONLY;
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MAX(LENGTH(ENAME)) FROM emp)
--ORDER BY 1
--FETCH FIRST 1 ROW ONLY
union
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MIN(LENGTH(ENAME)) FROM emp)
ORDER BY 1
FETCH FIRST 1 ROW ONLY;
One method uses aggregation and union all:
select min(name) keep (dense_rank first order by len(name) asc), min(len(name))
from emp
union all
select min(name) keep (dense_rank first order by len(name) desc, max(len(name))
from emp;
The keep syntax is Oracle's rather verbose way of having a "first" aggregation function.

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;

ORACLE SQL retrieve n rows without subqueries or derived tables

I'm doing my SQL exercises but I got stuck in one. I need to retrieve the employees with the two highest salaries, but I can't use any type of subquery or derived table. I do it with a subquery like this:
SELECT *
FROM (SELECT * FROM emp ORDER BY sal DESC) new_emp
WHERE ROWNUM < 3;
I also know that this can be achieved using the WITH clause, but I'm wondering if there is any alternative to this.
PS: I'm using Oracle 11.
If you are Oracle version 12.1 or above you can use a row limiting clause. In your case you would just use the subquery plus the row limiting clause like so:
SELECT * FROM emp
ORDER BY sal DESC
FETCH FIRST 5 ROWS ONLY;
Source: https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#top-n
This is actually a pathetic method, in my opinion, but you can use a join:
select e.col1, e.col2, . . .
from emp e left join
emp e2
on e2.salary >= e.salary
group by e.col1, e.col2, . . .
having count(distinct e2.salary) <= 2;
Note: this is really equivalent to a dense_rank(), so if there are ties, you'll get more than two rows. It is easy enough to fix this (assuming you have a unique identifier for each row), but the fix complicates the logic and hides the basic idea.
A good exercise should help to prepare to solve practical problems. So the important thing in this one is not the usage of subquery but to realize that the two highes salaries can have hunderts of employees.
While using the #MT0 view workaround this is the query
CREATE VIEW sal_ordered_emps AS
SELECT e.*,
row_number() over (order by sal desc) as RN
FROM SCOTT.emp e
ORDER BY sal DESC;
select e.* from scott.emp e join
sal_ordered_emps soe on e.sal = soe.sal and rn <= 2
;
result as explained can be more than 2 records
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 19.04.1987 00:00:00 3000 20
7839 KING PRESIDENT 17.11.1981 00:00:00 5000 10
7902 FORD ANALYST 7566 03.12.1981 00:00:00 3000 20
This is cheating but... instead of using a subquery you can define a view:
CREATE VIEW sal_ordered_emps AS
SELECT *
FROM emp
ORDER BY sal DESC;
Then you can do:
SELECT * FROM sal_ordered_emps WHERE ROWNUM < 3;
Alternatively, you can do it with a pipelined function...
CREATE OR REPLACE PACKAGE emp_pkg
AS
TYPE emp_table IS TABLE OF EMP%ROWTYPE;
FUNCTION get_max_sals(
n INT
) RETURN emp_table PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY emp_pkg
AS
FUNCTION get_max_sals(
n INT
) RETURN emp_table PIPELINED
AS
cur SYS_REFCURSOR;
in_rec EMP%ROWTYPE;
i INT := 0;
BEGIN
OPEN cur FOR SELECT * FROM EMP ORDER BY SAL DESC;
LOOP
i := i + 1;
FETCH cur INTO in_rec;
EXIT WHEN cur%NOTFOUND OR i > n;
PIPE ROW(in_rec);
END LOOP;
CLOSE cur;
RETURN;
END;
END;
/
SELECT *
FROM TABLE( emp_pkg.get_max_sals( 2 ) );
This solution use no subquery, but requires three steps:
-- Q1
select max(sal) from scott.emp;
-- Q2
select max(sal) from scott.emp where sal < {result of Q1};
select * from scott.emp where sal in ({result of Q1},{result of Q2});
General you'll need N+1 queries to get top-N salaries emps.