Updating rows based on another table - sql

I created a table called SALE_REP with 4 columns, employee_id, name, salary and commission_pct.
I populated the SALE_REP table from an existing EMPLOYEES table. Now I want to update the salaries of some of the employees in the SALE_REP table using a subquery based on the values from another table;
update sale_rep
set salary = (select salary from employees
where job_id = 'ad_vp')
where employee_id = (select employee_id from employees
where commission_pct = 0.35);
But this gets;
SQL Error: ORA-01427: single-row subquery returns more than one row
01427. 00000 - "single-row subquery returns more than one row"
*Cause:
*Action:
What am I doing wrong, and how can I perform the update successfully?

You have two subqueries, and if you data is based on the standard HR schema's employee table then both will return multiple rows.
The second is straightforward; the = needs to be in:
where employee_id in (select employee_id from employees
where commission_pct = 0.35)
... which matches three rows in the employee table in my schema. (Although as you said your sale_rep table is populated from employees and has the commission_pct column you don't really need to use a subquery here - the filter value exists on the table you're updating, so you could potentially just do where commission_pct = 0.35).
The first is more difficult and you'll need to define what you want to actually happen. You could, for example, pick the highest salary from those matching the specified job_id:
set salary = (select max(salary) from employees
where job_id = 'SA_REP')
I've picked 'SA_REP' as that looks like it might be a sales rep, and that has 30 matching rows with 20 different values in my schema. Based on your edit, there are two rows in my schema for AD_VP, but both have the same salary; in which case using max() might be OK, or you could use distinct:
set salary = (select distinct salary from employees
where job_id = 'AD_VP')
But that is very specific to the data you have at this point in time, so it isn't going to be a good general pattern.
Putting those together you could do:
select employee_id, salary from sale_rep where commission_pct = 0.35;
EMPLOYEE_ID SALARY
----------- ----------
156 10000
157 9500
158 9000
update sale_rep
set salary = (select max(salary) from employees
where job_id = 'AD_VP')
where employee_id in (select employee_id from employees
where commission_pct = 0.35);
3 rows updated.
select employee_id, salary from sale_rep where commission_pct = 0.35;
EMPLOYEE_ID SALARY
----------- ----------
156 17000
157 17000
158 17000
More generally there probably needs to be some connection between the row you're updating and the value you're choosing though, other than the filter on commission percentage, which doesn't look related to the job. That does seem to be what you want in this case though.

Related

single-row subquery returns more than one row in oracle in HR schema

select employee_id, first_name, job_id, salary
from employees where salary < ( select SALARY
FROM EMPLOYEES
WHERE JOB_ID='IT_PROG');
and I found an error like the following :
ORA-01427: single-row subquery returns more than one row
Looks like there are "many" employees whose job_id = 'IT_PROG'. In that case, subquery returns "many rows" and your query results in an error.
It depends on what you want to do in such a case; for example, you might want to return rows for employees whose salary is lower than minimum salary for IT_PROG, so that would be
SELECT employee_id,
first_name,
job_id,
salary
FROM employees
WHERE salary < (SELECT MIN (SALARY) --> note MIN function here
FROM EMPLOYEES
WHERE JOB_ID = 'IT_PROG');

Selecting the record(s) with the "second" highest something

I have written the following SQL commands for retrieving data from a table called Employee.
I was able to get the highest/maximum salary as well as the second highest/maximum salary, but I am having difficulty writing the same when the whole record needs to be returned.
Select all the employees.
SELECT * FROM Employee
Return the highest salary. This returns the maximum salary amount which is 90000
SELECT MAX(salary) FROM Employee
Return the employee record with the highest salary. This returns all the records of the person/people with their salary being the maximum salary which is 90000 that is only John Henry in this case.
SELECT *
FROM Employee
WHERE salary = ( SELECT MAX(salary) FROM Employee )
Return every other employee record; i.e. everyone except the one with the highest salary.
SELECT *
FROM Employee
WHERE salary != ( SELECT MAX(salary) FROM Employee )
Return the second highest salary. This returns the second maximum salary amount which is 85000
SELECT MAX(salary) FROM Employee
WHERE salary != ( SELECT MAX(salary) FROM Employee )
Return the employee record with the second highest salary. This returns all the records of the person/people with their salary being the second maximum salary which is 85000 that is only Michael Greenback in this case.
I am stuck in this... I tried using HAVING as an extra condition, but however I arrange it to specify a condition, I get syntax errors. How do I do this?
Window functions are the built-in functionality to do this. In particular, dense_rank():
select e.*
from (select e.*, dense_rank() over (order by salary desc) as seqnum
from employee e
) e
where seqnum = 2;
This is a SQL Server solution but can be easily re-written using limit N instead of top N. If your database doesn't support window functions, you could try this. If it does, Gordon's solution is the way to go.
with cte as
(select max(salary) as second_max
from employee
where salary in (select distinct top 2 salary -- top n is what makes this scalable
from employee
order by salary asc)) -- get top 2 salaries and sort them
select *
from employee
where salary = (select second_max from cte);

Unexpected result of a SQL query

Can anyone explain why this query:
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id IN (SELECT department_id
FROM employees
WHERE last_name LIKE '%u%'
)
AND salary > (SELECT AVG(salary)
FROM employees);
returns way less rows than this nested one:
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id IN (SELECT department_id
FROM employees
WHERE last_name LIKE '%u%'
AND salary > (SELECT AVG(salary)
FROM employees);
)
The first returns all employees who meet the following conditions:
The employee is in a department has a "u" employee.
The employee has a salary larger than the average.
The second returns all employees who meet these conditions:
The employee is in a department that has a "u" employee who has a salary larger than the average.
The two are very different conditions. I wouldn't expect them to return the same result set.
Also, whenever you have more than one table in a query, you should use table aliases that are abbreviations of the table name and you should qualify all column names.

Count and group by not working as expected

select count(*),manager_id
from departments
group by manager_id;
this is my idea of how to, but it dosent gives me the amount of employees for each manager
I suspect you are selecting from the wrong table, the logic seems correct but the fact that you are selecting from a table call departments is a little suspicious.
Do you have an employee tables? Does it contains a manager_id column? If so:
select count(*),manager_id
from employees
group by manager_id;
If employee tables has only department_id column then :
SELECT d.manager_id,count(*)
FROM employees e
INNER JOIN departments d
ON(e.department_id = d.id)
Using the sample table from the HR schema
select MANAGER_ID, count(*), count(distinct EMPLOYEE_ID)
from HR.EMPLOYEES
group by MANAGER_ID
order by 1 nulls first;
gives
MANAGER_ID COUNT(*) COUNT(DISTINCTEMPLOYEE_ID)
---------- ---------- --------------------------
1 1
100 14 14
101 5 5
102 1 1
Note the first row, with manager IS NULL - i.e. there is a one employee without a manager.
Not also that I use both count(*)and count(distinct EMPLOYEE_ID). This is not relevant for this table, where EMPLOYEE_ID is PK, but in general case the former returns the number of record the latter the number of employees (which can be lower).
I have faced a similar problem of yours.
Try adding inside the count the id that you are counting ie employeeid.
If it still doesnt work after that try adding the same id in the group by.

What does where do in the below query?

SELECT
COUNT(emp.empNo)
FROM
Employee emp
WHERE
NOT EXISTS (SELECT dept.empNo
FROM department dept
WHERE emp.empNo = dept.empNo);
What does the where condition(where emp.empNo = dept.empNo) signify in the above query? I get different results with and without the where condition. I'm new to Oracle. Can any one help me to understand?
your query displaying count of employees which are not present in emp table but present in dept table.
suppose we have two tables emp and dept :
emp dept
1 1
2 2
3 3
4 4
5 5
6
7
from the given table we have emp 1 to 5 in both of the tables but in dept table having 2 employees (6,7)which are not present in emp table and your query is displaying count for those emp i.e 2
The query means that you're looking for only those employees, for which it does not exist a department with the same empNo as the employee's empNo.
I guess this is a query to find those employees which are not managers of any department (if we assume that the department's empNo is the empNo of the department's manager).
Still, it would be better if you provide the schema of the employee and the department tables.
The query is basically looking for the number of employees who don't belong to a department.
NOT EXISTS means that the query enclosed returns no rows. So, for any employee where no matching rows are found in the Department table they are counted.
Same as saying
SELECT
COUNT(emp.empNo)
FROM
Employee emp
WHERE
emp.EmpNo NOT IN ( SELECT
empNo
FROM
department)