Update values using joins and where - sql

I've tried the following commands:
UPDATE staff SET salary = (salary * 1.1)
where branchno = (select branchno from branch where city = 'London');
update salary from staff s join branch b on s.branchno = b.branchno
where b.city = 'London' set salary = salary * 1.1;
However, I get this back as an error:
> ERROR: more than one row returned by a subquery used as an expression
Any ideas? essentially I want to update all members of staff's salaries by 10% that live in London, but I must join the Staff and Branch table to get the branches location.

Your query transformed to proper join syntax:
UPDATE staff s
SET salary = (salary * 1.1)
FROM branch b
WHERE b.city = 'London'
AND s.branchno = b.branchno;
This avoids the reported error. The manual has more on UPDATE.

Related

How to use UPDATE JOIN correctly?

I tried to update a table row as below:
update EMPLOYEE set Salary=Salary * 1.15 where Dno=1;
which works fine, but I wanted to learn how to use UPDATE JOIN. so I use the Department Name instead of DNo.
I wrote below code:
update EMPLOYEE set Salary=e.Salary * 1.15 from EMPLOYEE e join DEPARTMENT d on e.DNo=d.DNumber where d.DName='Headquarters';
But the result for above code is that the SQL Command updates all the rows in EMPLOYEE table.
Where did I do wrong?
In BigQuery, change this to a filter in the where clause:
update EMPLOYEE e
set Salary = Salary * 1.15
where exists (select 1
from DEPARTMENT d
where d.DNumber = e.DNo and
d.DName = 'Headquarters'
);
The above is standard SQL and should work in any database. If you want a FROM clause, then use:
update EMPLOYEE e
set Salary = e.Salary * 1.15
from DEPARTMENT d
where d.DNumber = e.DNo and
d.DName = 'Headquarters';
There are (at least) two different ways of implementing FROM in an update, the "SQL Server method" and the "Postgres" method. In the SQL Server method, the table being updated should be in the FROM clause. In the "Postgres method", the table cannot be in the FROM clause. BigQuery adheres to the "Postgres method".
The above actually works in both methods, though.
Try to use table alias name in update
update Emp
Set Salary = Emp.Salary * 1.15
From EMPLOYEE As Emp
join DEPARTMENT As dep On Emp.DNo = dep.DNumber
Where dep.DName = 'Headquarters';

Query For getting the Salary of employee

Insert into Employee values (1,'Abdul Rehman','Street No 12','Kamra Kalan')
Insert into Employee values (2,'Iram Bhatti','Street No 10','Attock')
Insert into Employee values (3,'Danial Aziz','Street No 12','Kamra Kalan')
Insert into Employee values (4,'Kashif Butt','Street No 10','Attock')
Insert into Employee values (5,'Zohaib Butt','Street No 13','Peshawar')
insert into Company values (1,'First Bank Co-Operation','Hydrabaad');
insert into Company values (2,'Small Bank Co-Operation','Kashmir');
Insert into Works values (1,2,5000)
Insert into Works values (2,1,40000)
Insert into Works values (1,3,56000)
Insert into Works values (1,4,8000)
Insert into Works values (2,2,78000)
Question:
Write a query for getting the name of employees who earn more than every employee of Small Bank Co operation.
My query Solution:
Select Employee.person_name from Works
inner join Employee on Employee.person_Id
=Works.Person_Id inner join Company on
Company.Company_Id=Works.Company_Id
and Salary>(Select Salary from works
Where Company.Company_name='Small Bank Co-Operation')
But This query not works for me how can I get this one?
I think the simplest solution is just to join all of the tables and then find the employee who has a salary equal to the max salary from the works table.
SELECT e.person_name
FROM employee e inner join works w
on e.person_Id = w.Person_Id
inner join company c
on w.Company_Id = c.Company_Id
WHERE c.Company_name = 'Small Bank Co-Operation'
and w.Salary = (SELECT max(works.Salary)
FROM works)
How much does an employee earn?
select person_id, sum(salary)
from works
group by person_id;
We can even extend this to see whether this is Small Bank employee:
select
person_id,
sum(salary),
max(case when Company_Id =
(select Company_Id from company where company_name = 'Small Bank Co-Operation')
then 1 else 0 end
) as is_small_banker
from works
group by person_id;
Now, use this to compare:
with salaries as
(
select
person_id,
sum(salary) as total,
max(case when Company_Id =
(select Company_Id from company where company_name = 'Small Bank Co-Operation')
then 1 else 0 end
) as is_small_banker
from works
group by person_id
)
select e.person_name
from employee e
join salaries s on s.person_id = e.person_id
where total > all
(
select total
from salaries
where is_small_banker = 1
)
order by e.person_name;
This is just one way to do this. You can do the same with NOT EXISTS for example (i.e. where not exists a Small Bank worker with the same or a higher salary).
Update
You have meanwhile tagged your request with SQL Server and told me that you are getting this error:
Msg 130, Level 15, State 1, Line 126 Cannot perform an aggregate function on an expression containing an aggregate or a subquery
Obviously, SQL Server has problems with the conditional aggregation. You can circumvent this by joining the compabny table instead:
with salaries as
(
select
w.person_id,
sum(w.salary) as total,
max(case when c.company_name = 'Small Bank Co-Operation' then 1 else 0 end
) as is_small_banker
from works w
join company c on c.company_Id = w.company_Id
group by w.person_id
);
Update 2
If the works table could only have one work (company and salary) per employee, the whole query would reduce to:
select e.person_name
from employee e
join works w on w.person_id = e.person_id
where salary > all
(
select salary
from works
where id_company =
(select company_Id from company where company_name = 'Small Bank Co-Operation')
)
order by e.person_name;

JOIN - 2 tasks - sql developer

I have 2 tasks:
1. FIRST TASK
Show first_name, last_name (from employees), job_title, employee_id (from jobs) start_date, end_date (from job_history)
My idea:
SELECT s.employee_id
, first_name
, last_name
, job_title
, employee_id
, start_date
, end_date
FROM employees
INNER JOIN jobs hp
on s.employee_id = hp.employee_id
INNER JOIN job_history
on hp.jobs = h.jobs
I know it doesn't work. I'm receiving: "HP"."EMPLOYEE_ID": invalid identifier
What does it mean "on s.employee_id = hp.employee_id". Maybe I should write sthg else instead of this.
2. SECOND TASK
Show department_name (from departments), average and max salary for each department (those data are from employees) and how many employees are working in those departments (from employees). Choose only departments with more than 1 person. The result round to 2 decimal places.
I have the pieces, but i don't know to connect it
My idea:
SELECT department_name,average(salary),max(salary),count(employees_id)
FROM employees
INNER JOIN departments
on employees_id = departments_id
HAVING count(department) > 1
SELECT ROUND(average(salary),2) from employees
I modified your queries a bit by improving table aliasing. Hopefully, if the right columns are present in the tables as you say, it should work:
SELECT s.employee_id, s.first_name, s.last_name,
hp.job_title, hp.employee_id,
h.start_date, h.end_date
FROM employees s
INNER JOIN jobs hp
on s.employee_id = hp.employee_id
INNER JOIN job_history h
on hp.jobs = h.jobs;
When we say on s.employee_id = hp.employee_id it means that if, for example, there is an employee_id = 1234 present in both the tables employees and jobs, then SQL will bring all the columns from both the tables in the same line that corresponds to employee_id = 1234. You can now pick different columns in the SELECT clause as if they are in the same/single table(which was not the case before joining). This is the main logic behind SQL joins.
As to your 2nd task, try the below query. I made some modifications in aggregation by introducing COUNT(DISTINCT s.employees_id). If the same employees_id is present twice for some reason, you still want to count that as one person.
SELECT d.department_name, avg(s.salary), max(s.salary), count(distinct s.employees_id)
FROM employees s
INNER JOIN departments d
on e.employees_id = d.departments_id
GROUP BY d.department_name
HAVING COUNT(DISTINCT s.employees_id) > 1;
Let me know if there is still any issue. Hopefully, this works.

Give a raise to people who work in X city?

Let's say these are the 2 tables:
workers[name, dep_id, salary]
and
department[id, name, city]
How can I achieve to raise the salary of those who work in a particular city?
I'd only know how to do it if the city was in the workers table (then it'd be just UPDATE workers SET salary = salary * 1.1 WHERE city = 'X'), but it doesn't work when the salary and city are in different tables.
You can use this query:
UPDATE workers w
SET salary = salary * 1.1
WHERE EXISTS (SELECT *
FROM departments d
WHERE d.id = w.dep_id
AND d.city = 'X')
You can use also other queries, depending on your specific system.
UPDATE w
SET w.salary = w.salary*1.1
FROM workers w
LEFT JOIN department d
ON d.id = w.dept_id
WHERE d.city = 'denver'
I believe this will work. Left joining to department will give you the extra columns you're looking for for each row in workers.
UPDATE
w
SET
w.salary = w.salary * 1.1
FROM
workers w
INNER JOIN
departments d
ON
w.dep_id = d.id
WHERE
d.city = 'X'
Best and most safe way to do any data update is to first select rows which you want to update.
So First step will be
SELECT (*) // Select all
FROM
workers w // From workers
INNER JOIN
departments d // and departments
ON
w.dep_id = d.id // where workers dep_id vakue is in
// departments id column
// INNER JOIN get ONLY that data
WHERE
d.city = 'X' // and filter by city name
now you can replace select part with
UPDATE
w // Update table which name or alias is w
SET
w.salary = w.salary * 1.1 / set salary to current salary * 1.1

Replacing a table value with the previous expression in oracle

Ok so I am having the following scenario
I have a table called employees and have to replaced the last names for some of the people there under the following conditions:
1-The last name must be replaced only to those employees who work on Oxford.
2-Their new last name is going to be the last name of the person that has their employee number -1 ( for instance employee#173 should have now employee#172 last name instead)
This is how I started the query:
select last_name,num_emp
from employees
where num_emp in(
select e.num_emp
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
And I did a second query to make sure which values were going to replace which
Select last_name,num_emp
from employees
where num_emp in(
select (e.num_emp-1)
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
Now I thought I could do this and make the code work... but it didn't:
update employees
set last_name=(select last_name
from employees
where num_emp in(
select (e.num_emp-1)
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
Got error saying unexpected end of SQL command...
So I thought on making a change because I believed having too many values on the set was not the point and here is how I did it for last time:
update employees
set last_name=(select last_name
from employees)
where num_emp =(
select (e.num_emp-1)
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
Got an error that says is missing right parenthesis, which I know it does not express whaat the issue is. I know I am missing something and part of the sintaxis is wrong as well as I may need to créate another table and add those values so that they get saved there and I can compare them with the original ones, but at this point I am totally blocked and can't discover what is the mistake I am doing. Please help me I'd really apprecciate it!
You are getting confused with what to update and what to update with in your statements.
Here is what to update. I use IN clauses to make it plain. An EXISTS clause would also be appropriate.
update employees
set last_name = ...
where num_dept in
(
select num_dept
from departments
where id_office in
(
select id_office
from office
where city = 'Oxford'
)
);
And here is what to update with:
set last_name =
(
select last_name
from employees prev_employee
where prev_employee.num_emp = employee.num_emp - 1
)
You should use the analytical lag function, then you also fill in gaps if for example employee 172 doesn't exist and you have to put the name of employee 171 in 173.
Your select should be something like this
with new_emp as
(select last_name,lag(last_name, 1, 0) over (order by num_emp) as new_last_name, num_emp
from employees)
select *
from new_emp
where num_emp in(
select e.num_emp
from employees e
join departments using(num_dept)
join office using(id_office)
where city='Oxford');
This select will give you the original last name, new last name, employee number.
Then afterwards your update should be this:
update employees x
set last_name = (with new_emp as
(select last_name,lag(last_name, 1, 0) over (order by num_emp) as new_last_name, num_emp
from employees)
select new_last_name
from new_emp ne
where ne.num_emp = x.num_emp)
where x.num_emp in(
select e.num_emp
from employees e
join departments using(num_dept)
join office using(id_office)
where city='Oxford');