How do I subquery the right results - mysql

I am trying to do a join subquery to return just employee names that earn less than 46000 and I can get it to work by also returning the employee id but not without it.
This is how Im doing it.
Select e.eid, e.ename
From employee_table e
Inner Join (
Select salary, eid
from salary
Where salary > 46000
) as s
On e.eid = s.eid;

This beacuse you are using a dinamic temporary table and if you don't select the eid column your temporary dinamica table don't contain this values and the on clause in join fails
Select e.eid, e.ename
From employee_table e
Inner Join (
Select salary, eid
from salary
Where salary < 46000
) as s
On e.eid = s.eid;
you can use an inner join without dinamic temporary table
Select e.eid, e.ename
From employee_table e
INNER JOIN salary s On e.eid = s.eid
where s.salary < 46000

So the salary isn't stored in the employee table, but in a separate salary table. The salary table contains the employee ID. This makes this a 1:n relation, i.e. one employee can have more than one salary.
I don't know your tables, so I don't know the reason for this. Maybe an employee can have many jobs, or there are part salaries like a base salary and additional salaries, or there is a date range stored with the salary to indicate when it is/was valid. I don't know.
Let's say, we can simply add an employee's salaries to get the total. Then we select the employee names from the employee table where we find a salary less than 46000 in the salary table.
select ename
from employee
where eid in
(
select eid
from salary
group by eid
having sum(salary) < 46000
);

Related

How to handle SQL subqueries with sums

I am practicing queries on an example database in MySQL.
I have an employee table with a primary key of emp_id.
I have a works_with table with a composite key of emp_id and client_id. It also has a column of total_sales.
I am trying to write a query that returns the name of any employee who has sold over 100,000 total.
I was able to return the employee id and total for sums over 100,000 like so:
SELECT SUM(total_sales) AS total_sales, emp_id
FROM works_with
WHERE total_sales > 100000
GROUP BY emp_id;
But I am unsure how to use this to also get employee name. I have tried nested queries but with no luck. For example when I try this:
SELECT first_name, last_name
FROM employee
WHERE emp_id IN (
SELECT SUM(total_sales) AS total_sales, emp_id
FROM works_with WHERE total_sales > 100000
GROUP BY emp_id
)
I get Error 1241: Operand should contain 1 column(s). I believe this is because I am selecting two columns in the nested query? So how would I handle this problem?
Just join:
select sum(w.total_sales) as total_sales, e.first_name, e.lastnmae
from works_with w
inner join employee e on e.emp_id = w.emp_id
group by e.emp_id
having sum(w.total_sales) > 10000;
Note that I used a having clause rather than the where clause: presumably, you want to sum all sales of each employee, and filter on that result. Your original queried sums only individual values that are greater than 100000.
Adding to GMB's solution.
Take your existing Select and wrap it in a Derived Table/CTE:
SELECT e.first_name, e.last_name, big_sales.total_sales
FROM employee as e
join
(
SELECT SUM(total_sales) AS total_sales, emp_id
FROM works_with
GROUP BY emp_id
HAVING total_sales > 100000
) as big_sales
on e.emp_id = big_sales.emp_id
Now you can show the total_sales plus employee details. Additionally this should be more efficient, because you aggregate & filter before the join.
If you only need to show the employee you can use a SubQuery (like the one you tried), but it must return a single column, i.e. remove the SUM from the Select list:
SELECT first_name, last_name
FROM employee
WHERE emp_id IN (
SELECT emp_id -- , SUM(total_sales) AS total_sales
FROM works_with
GROUP BY emp_id
HAVING SUM(total_sales) > 100000
)

SQL GROUP BY and MIN to find people with minimum salary in each department [duplicate]

This question already has answers here:
Group by minimum value in one field while selecting distinct rows
(10 answers)
Closed 4 years ago.
I have a sql query that outputs employees who have the minimum salary across departments. It does so by finding the minimum salary for each department and finding people with salaries that match ANY of those. In this case, Person 1 can belong to department A and have a salary of 70k (even though her department's minimum is 45k) and be returned in the query if another department's minimum salary is 70k. However, what if I instead want to output names of people who have the minimum salary for their respective department (so Person 1 would not be returned anymore). Here is the current sql query:
SELECT first_name, last_name, salary, department_id
FROM employees
WHERE salary IN
( SELECT MIN(salary)
FROM employees
GROUP BY department_id
);
If you have MySQL 8.0 then the simplest approach is using window function:
SELECT *
FROM (SELECT *, RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS r
FROM tab) sub
WHERE r = 1;
Or:
SELECT first_name, last_name, salary, department_id
FROM employees e
WHERE (department_id,salary) IN
( SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id);
Instead fo a IN clause you can also use an inner join
SELECT first_name, last_name, salary, department_id
FROM employees
INNER JOIN ( SELECT department_id, MIN(salary) min_sal
FROM employees
GROUP BY department_id
) t on t.department_id =employees.department_id
and employees.salary = t.min_sal;
this should be better for performance

Subquery returns more than 1 row in SQL?

So I have Two Tables called Emp and Dept..
Emp has ssn, name, supssn, salary, depno
Dept has Dno, name, mgrssn
I'm supposed to get names of those managers who are making less than some of his employees
Right now I have:
SELECT DISTINCT Emp.name
FROM Emp CROSS JOIN Dept
WHERE ((SELECT Emp.salary
FROM Emp, Dept)>(SELECT Emp.salary
FROM Emp, Dept
WHERE(Emp.name IN (SELECT Emp.name
FROM Emp CROSS JOIN Dept
WHERE ssn = mgrssn)))) AND (SELECT Emp.depno
FROM Emp, Dept)=(SELECT Emp.depno
FROM Emp, Dept
WHERE(Emp.name IN (SELECT Emp.name
FROM Emp CROSS JOIN Dept
WHERE ssn = mgrssn)));
What exactly am I missing or adding too much right now?
you really need to be patient and organize your question, sir..
but if I understand it correctly, you may try this..
(I assume supssn is the ssn of the manager)
SELECT DISTINCT sup.name
FROM emp e join emp sup on e.supssn = sup.ssn
WHERE sup.salary < e.salary

How do I return the employees with salary greater than 15000?

I have two tables, EMP and Salary, where on EMP table I have the following fields:
id, emp_name,designation
And on the Salary table I have the following fields:
id, emp_id, salary
How can I get the name of employee whose salary is greater than 15000?
Use JOIN and WHERE clause
SELECT emp_name
FROM EMP
JOIN Salary
ON EMP.id = Salary.emp_id
WHERE salary > 15000
You can use an inner query, like this:
SELECT emp_name
FROM emp
WHERE id IN (SELECT emp_id FROM salary WHERE salary > 15000)
Is this homework? I will just give you the necessary hints rather than a complete statement:
The reason for salary being a table on its own is that an employee can have more than one salary. (Otherwise salary would just be a field in emp table).
So first join emp and salary to get all salaries for all employees. Then group by employees to get the sum of the salaries for each employee. Then at last filter your results to salaries over 15000. Do you know already how to filter group results?
There is more than one way to write a correct statement. I am sure you will find one using the hints given. Good luck!

Question regarding writing SQL query

Consider I have two tables/columns:
Employee - > EmpId, DeptNo, EmpName, Salary
Department -> DeptNo, DeptName
Write a query to get employee names who is having maximum salary in all of the departments.
I have tried this:
Select max(salary),empname
from Employee
where deptno = (select deptno
from department
where deptname in('isd','it','sales')
Is it correct? Actually it's a interview question.
This is an example of groupwise max mysql pattern. One way to do it would be:
SELECT e.salary, e.name, d.deptname
FROM Employee AS e
JOIN (
SELECT max(salary) AS max_sal, deptno
FROM Employee
GROUP BY deptno
) AS d_max ON (e.salary=d_max.max_sal AND e.deptno=d_max.deptno)
JOIN Department AS d ON (e.deptno = d_max.deptno)
Though it will return more than one row for a department if more than one employee has a maximum salary in a department
Personally I'd use a cte and row_number for a question like this. For example:
with myCTE as
(
select e.empName, e.salary, d.deptName,
row_number() over (partition by e.deptNo order by e.salary desc) as rn
from Employee as e
inner join Department as d
on d.DeptNo=e.DeptNo
)
select m.empName, m.deptName, m.salary
from myCTE as m
where m.rn=1
In the case of ties (two employees in the same department have the same max salary) then this is non-deterministic (it will just return one of them). If you want to return both of them then change the row_number to a dense_rank.