Table employee has two columns:
ID
NAME
Table external_job also has two columns:
ID
SALARY
I have to get one person who got the maximum salary.
The result must have three columns and one row:
ID
NAME
SALARY
I made a query but the client asked me not to use a sub-select query.
How can I do in this case?
My query is:
select *
from (select a.id,
a.name,
(select sum(salary)
from external_job b
where b.id = a.id) salary
from employee a
order by salary desc)
where rownum = 1
Use order by and some method for limiting the results to one row. In standard SQL this is:
select ej.id, e.name, ej.salary
from employee e join
external_job ej
on ej.id = e.id
order by ej.salary
fetch first 1 row only;
Not all databases support fetch first. Some use limit or select top or even more arcane constructs.
Assumption is ID is primary key on both sides.
select ID, NAME, SALARY from employee e , external_job a where e.id= a.id
order by salary desc
limit 1
Related
I have a code that outputs Department Names and their number of workers.
SELECT department_name,COUNT (employee_id) FROM EMPLOYEES
JOIN DEPARTMENTS
ON employees.department_id=departments.department_id
GROUP BY department_name
ORDER BY count(employee_id) DESC
I want to select the first three department names that have the largest number of workers. . When I WHERE, I get three rows, but the output is not true.
SELECT department_name,COUNT (employee_id) FROM EMPLOYEES
JOIN DEPARTMENTS
ON employees.department_id=departments.department_id
WHERE rownum <= 4
GROUP BY department_name
ORDER BY count(employee_id) DESC
What can you recommend to me about this issue? Also, I will use this query in a PL/SQL block.
THANKS!
That rownum clause happens before the sort. You can either use
fetch first 3 rows only
after the order by clause, if using Oracle 12c or above, or with rownum use a subquery -
select * from (
your query here
)
where rownum < 4;
Tables:
Department (dept_id,dept_name)
Students(student_id,student_name,dept_id)
I am using Oracle. I have to print the name of that department that has the minimum no. of students. Since I am new to SQL, I am stuck on this problem. So far, I have done this:
select d.department_id,d.department_name,
from Department d
join Student s on s.department_id=d.department_id
where rownum between 1 and 3
group by d.department_id,d.department_name
order by count(s.student_id) asc;
The output is incorrect. It is coming as IT,SE,CSE whereas the output should be IT,CSE,SE! Is my query right? Or is there something missing in my query?
What am I doing wrong?
One of the possibilities:
select dept_id, dept_name
from (
select dept_id, dept_name,
rank() over (order by cnt nulls first) rn
from department
left join (select dept_id, count(1) cnt
from students
group by dept_id) using (dept_id) )
where rn = 1
Group data from table students at first, join table department, rank numbers, take first row(s).
left join are used is used to guarantee that we will check departments without students.
rank() is used in case that there are two or more departments with minimal number of students.
To find the department(s) with the minimum number of students, you'll have to count per department ID and then take the ID(s) with the minimum count.
As of Oracle 12c this is simply:
select department_id
from student
group by department_id
order by count(*)
fetch first row with ties
You then select the departments with an ID in the found set.
select * from department where id in (<above query>);
In older versions you could use RANK instead to rank the departments by count:
select department_id, rank() over (order by count(*)) as rnk
from student
group by department_id
The rows with rnk = 1 would be the department IDs with the lowest count. So you could select the departments with:
select * from department where (id, 1) in (<above query>);
In my Employee table, I wanted to find the 3rd highest salary. Someone provided me with the following query to do this:
SELECT *
FROM employee C1
WHERE 3 = (SELECT Count(DISTINCT( C2.salary ))
FROM employee C2
WHERE C2.salary >= C1.salary)
This query works, but I don't how it works. What kind of query is this?
As others have said, this type of query is called a correlated sub-query. It's a sub-query because there is a query within a query and it's correlated because the inner query references the outer query in its definition.
Consider the inner query:
SELECT Count(DISTINCT( C2.salary ))
FROM employee C2
WHERE C2.salary >= C1.salary
Conceptually, this inner query will be evaluated once for every row produced by the outer query before the WHERE clause is applied, basically once for every row in employee. It will produce a single value, the count of rows from employee where the salary is less than the salary of the outer row.
The outer query will only return records where the value produced by the inner query is exactly 3. Assuming unique salary values, there is only one row from the employee table where there will be exactly 3 records with a salary value greater than or equal to it (the one row) and that one row is necessarily the third-highest salary value.
It's clever, but unnecessarily weird and probably not as optimal as something more straightforward.
Maybe a better solution would have been
SELECT TOP 1 *
FROM (
SELECT TOP 3 * FROM employee ORDER BY Salary DESC
) t
ORDER BY Salary ASC
Easier to read and more efficient than a correlated sub-query.
You can also use Dense_Rank to rank the salaries greatest to least, then select the ones that are ranked 3rd. This will also prevent you from getting the wrong salary if the top 2 are identical like the other answers above mine are doing. This has a better looking execution plan than the Distinct count one also
SELECT *
FROM (
SELECT *,
DENSE_RANK() OVER (ORDER BY Salary DESC) salary_rank
FROM employee e
) t
WHERE salary_rank = 3
Could also rewrite this with a common table expression.
WITH top_three
AS
(
SELECT TOP 3 * FROM employee ORDER BY Salary DESC
)
SELECT TOP 1 *
FROM top_three
ORDER BY Salary ASC;
Or, if you need to look for other ranks in this you can use row_number().
WITH ranked
AS
(
SELECT rank = ROW_NUMBER()OVER(ORDER BY Salary DESC), *
FROM employee
ORDER BY Salary DESC
)
SELECT *
FROM ranked
WHERE rank = #whatever_rank_you_want;
I have an 'employee' table with
create table employee
(
e_number int,
e_name varchar(20),
salary money,
hire_date date
)
Now I want to display only the name of the employees who have the same name but different salary.
I tried select e_name,count(*) from employee group by e_name having count(*)>1;
but cannot combine it with "the same salary" section. Any help?
This assumes that you want the names of both of the people listed:
SELECT e1.e_name
FROM employee e1, employee e2
WHERE e1.e_name = e2.e_name
AND e1.salary <> e2.salary;
If you only want each name listed once, you would use a SELECT DISTINCT instead of the SELECT.
If your goal is to express this in the having clause:
Select name
from employee
group by name
having
count(*) > 1
and min(salary) != max(salary)
order by name
SELECT employee1.e_name, employee1.Salary, Employee2.Salary
FROM Employee employee1
JOIN Employee employee2
on employee1.name = employee2.name
AND Employee1.Salary <> Employee2.Salary
AND Employee1.E_Number <> employee2.E_Number
Basically get every employee, join it to every other employee via name, where the employee number is different (so don't join to yourself) and salary is different.
You probably don't need to check that employee number is different because 1 employee can only have 1 salary in your table design
Use a join, but importantly use a greater-than comparison, rather than a not-equals, to avoid duplicates:
SELECT e1.e_name as name1, e2.e_name as name2
FROM employee e1
JOIN employee e2 ON e1.e_name = e2.e_name
AND e1.salary > e2.salary;
Note also that the ON condition contains the salary comparison. It is a common misconception that the join on condition may only contain key-related comparisons. Doing this can have significant performance benefits, especially when further joins are made, because the ON condition is executed as the rows are joined - which discards non-matches immediately, whereas WHERE conditions are executed as a filter on the entire result set of the joins.
You just want the count of distinct salaries, not the count of all records.
select e_name,count(distinct salary)
from employee
group by e_name
having count(distinct salary)>1
(Drop the count in the select if unneeded - included since it was in your example)
First filter salary not double (not in), then grouping by e_name having count > 1
SELECT A.e_name
FROM employee A
WHERE A.salary NOT IN (SELECT salary FROM employee WHERE id != A.id)
GROUP BY A.e_name
HAVING COUNT(A.e_name) > 1
I want to find the largest sale for each of my employees (and display the name of the employee). In MySQL, it's pretty straightforward:
select *
from employee, sale
where employee.id = sale.employee_id
group by employee_id
order by sale.total desc
This does pretty much what one would expect, it would return a list of employees and end up returning the largest sale record with the employee row.
But, Oracle does not allow you to return columns which are not group by expressions when a group by clause is used. Do this make what I do in MySQL "impossible" in Oracle? Or is there some workaround? I suppose I could perform some sort of subquery, but not sure if there is another way to do this that wouldn't quite be so complicated to construct.
Get rid of your select * and replace it with just the columns you need and then group by all the "non-processed" columns.
You'll end up with something like:
select employee.id, employee.name, max(sale.total)
from employee, sale
where employee.id = sale.employee_id
group by employee.id, employee.name
order by max(sale.total) desc
It's a pain - I've had to do this many times before - but just add all the related columns to your group by
To get the largest sale you can use group by with the max function.
select e.name, max (s.total)
from employee e, sale s
where e.id = s.employee_id
group by e.name
order by s.total desc
I have made an assumption that the employee name is in the name column of the employee table. I have also aliased the employee table and sales tables.
If you would prefer to see the total sales for an employee, you can swap out max() and use sum() instead.
Congratulations, you've learned just enough to be dangerous!
What you really want is each employee's largest sale. Now it happens that sorting them by sales amount desc and then grouping them works in MySQL, even though that isn't legal according to ANSI SQL. (Basically, MySQL is arbitrarily grabbing the first row for each employee, and that "works" because of the sort.)
The right way to do this is not to rely on the side of effect of the sort doing what you want; instead you should explicitly ask for what you want: the largest sale for each employee. In SQL that's:
select employee.id, max( sale.total)
from employee, sale
where employee.id = sale.employee_id
group by employee.id
order by 2
If you want to select an employee with a highest sale, you don't need GROUP BY here at all.
All you need is to select the highest sale and join it back to the employees:
SELECT *
FROM (
SELECT sale.*, ROW_NUMBER() OVER (ORDER BY total DESC) AS rn
FROM sale
) s
JOIN employee e
ON e.id = s.employee_id
AND s.rn = 1
This will select a single row with a total highest sale.
If you want to select per-employee highest sale, just add a PARTITION BY clause to your query:
SELECT *
FROM (
SELECT sale.*, ROW_NUMBER() OVER (PARTITION BY employee_id ORDER BY total DESC) AS rn
FROM sale
) s
JOIN employee e
ON e.id = s.employee_id
AND s.rn = 1