Update table column based on two other table values - sql

I need to update a column in one of my tables based on data from 2 other tables.
So I want the column isAvailable, in the table questionObjectives, to be set to 1 based on 2 conditions and this is what I have:
UPDATE
dbo.questObjectives
SET
isAvailable = 1
FROM
dbo.questObjectives qo
INNER JOIN
dbo.dungeonList dl
ON
qo.questID = dl.questID
WHERE dl.dungeonType = 17
AND qo.objectiveID IN(SELECT objectiveID FROM gameMissions)
So to translate, isAvailable should be set to 1 if:
the linked dungeonList type is 17
the questionObjectives objectiveID is in the table gameMissions
So I thought I had my logic right, but I keep getting this error:
'invalid column name isAvailable.'
But it is there. It is in the questionObjectives table so I'm not sure what I'm doing wrong.
Any ideas?
Thanks!

Is this what you want?
update qo
set qo.isavailable = 1
from questObjectives qo
inner join dungeonList dl on qo.questID = dl.questID
where
dl.dungeonList = 17
and exists (select 1 from gameMissions gm where gm.objectiveID = qo.objectiveID)
The main problem with your query is that you have target table questObjectives both in the update and from clauses; you should have it just once, in the from clause, and then refer to the alias in the update clause.
I also rewrote the in condition as a correlated subquery with exists - the logic is the same, but this might perform better.

Related

Update a column after select where does not exists

How can i update a column after i have selected records which do not exist from another table.
Need to update Status column to 0 when there are certain records which do not exist.
SELECT *
FROM [BankingServicesReconciliations].[dbo].[Test1] p1
WHERE p1.[Age] is not null and
Not EXISTS (SELECT * FROM [BankingServicesReconciliations].[dbo].[Test2] p2 WHERE ( p1.[Surname] =p2.[Surname]) )
Your code basically translates to an update:
UPDATE [BankingServicesReconciliations].[dbo].Test1
SET status = 0
WHERE Age is not null and
NOT EXISTS (SELECT 1
FROM [BankingServicesReconciliations].[dbo].[Test2] p2
WHERE p2.[Surname] = Test1.[Surname]
);
The only subtlety is that SQL Server doesn't allow you to declare an alias in the UPDATE clause. You could use a FROM clause but that hardly seems necessary in this case.
I prefer LEFT JOIN:
UPDATE p1
SET STATUS = 0
FROM [BankingServicesReconciliations].[dbo].[Test1] p1 LEFT JOIN
[BankingServicesReconciliations].[dbo].[Test2] p2 ON p1.[Surname] = p2.[Surname] and p2.[Age] IS NOT NULL
WHERE p1.[Age] IS NOT NULL
AND p2.[Surname] IS NULL
This one is way much cleaner and understandable than EXISTS approach and, you better believe me, is WAY MUCH FASTER!

Updating a column that is within a view

I have this simple view set in place which joins 3 different tables and displays data within my program. I noticed however, that I can update columns from the table PRODCODE like so:
update PRODCODE_VW set MAXGH = 5.00 where ORIGREC = 114406 --RETURNS 1 UPDATED
And it will update 1 record. However, when I do an update on ExpectedLevels, it will update 0 rows. I'm assuming this is because it is left joined. Is there a way to get around this by only altering the way the view is set up and not the update statement?
update PRODCODE_VW set EMIN = 5.00 where ORIGREC = 114406 --RETURNS 0 UPDATED
This is the view I have set in place:
IF EXISTS (SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_NAME = N'PRODCODE_vw')
DROP VIEW PRODCODE_vw
GO
CREATE VIEW dbo.PRODCODE_vw
AS
SELECT PRODCODE.STUFF,PRODCODE.ORIGREC,PRODCODE.PRODCODE,PRODCODE.PRODNAM,
C1JMASTER.C1JTYPE, EXPECTEDLEVELS.EMIN, EXPECTEDLEVELS.EMAX
FROM PRODCODE (NOLOCK)
LEFT JOIN C1JMASTER (NOLOCK)
ON PRODCODE.c1jcode = C1JMASTER.c1jcode
LEFT JOIN EXPECTEDLEVELS
ON PRODCODE.PRODCODE = EXPECTEDLEVELS.PRODCODE
GO
When you select ORIGREC = 114406 from the view, is there any value for EMIN, or it is null? Most likely, the ORIGREC 114406 does not have a matching record in the left joined table. Your update statement effectively filters on WHERE ORIGREC = 114406 AND PRODCODE.PRODCODE = EXPECTEDLEVELS.PRODCODE
You can target the left joined tables as long as your affected columns are all sourced from the same table in the view. However, if the left join would not return a EXPECTEDLEVELS row for the ORIGREC, your rows updated will be zero, because there is no matching row in the target table.

Oracle, update column in table 1, when related row does not exist in table 2

I have seen many answers that will update a table 1 when rows exist in table 2, but not one that works using a LEFT JOIN in selecting the rows, (for better performance). I have a solution to the update, but it will perform badly as it uses NOT IN.
So this SQL will update the tables as required, but looks to be very costly when run against large tables making it difficult to use.
update header
set status='Z'
where status='A'
and header.id not in (
select headerid
from detail
where detail.id between 0 and 9999999
);
Now I have a well performing query using a LEFT JOIN which returns the correct ids, but I have not been able to insert it into an update statement to give the same results.
The select statement is
select header.id
from header
left join detail on detail.headerid = header.id
where detail.headerid is null
and header.status='A'
So if I use this in the update statement as in:
update header
set status = 'Z'
where header.id = (
select header.id
from header
left join detail on detail.headerid = header.id
where detail.headerid is null and header.status='A'
)
Then I fail with:
ORA-01427: single-row subquery returns more than one row
I am expecting multiple header.id to be returned and want to update all these rows.
So I am still searching for a solution which will update the returned rows, using a well performing SQL select to return rows in table header, that do not have related rows in the detail table.
Any help would be appreciated, otherwise I will be left with the badly performing update.
Since you are expecting multiple header ID & the sub query returns multiple ID as you expected you should use IN
Try this
Update
header
Set status = 'Z'
Where
header.id IN (select
header.id
From
header
Left join
detail
On
detail.headerid = header.id
Where
detail.headerid is null
And
header.status='A')
I wouldn't put the condition on the outer table in the subquery. I am more comfortable writing this logic as:
update header h
set status = 'Z'
where not exists (select 1
from detail d
where d.headerid = h.id
) and
h.status = 'A';
If performance is an issue, indexes on detail(headerid) and header(status, id) and help.
typical, the next place I looked, I found an answer...
update header set status='Z' where not exists (select detail.headerid from detail where detail.headerid = header.id) and status = 'A'
Oh well, at least its here if anyone else wants to find it.
As the error states your subquery is returning more than one rows and you are using a = sign in your update query. = sign is not allowed if your query returns more than one records use either IN, NOT IN , EXISTS, NOT EXISTS as per your requirement

Update statement based on another table

I am trying to update column in table get it from another table and I have relation between two tables as parent have primary key "tbl_Inv_ClientItemsReturnOrders" and child have foreign key "tbl_Inv_ClientItemsReturnOrderDetails".
I try this
update U
set U.InventoryReturnReasonID =
(select InventoryReturnReasonID
from tbl_Inv_ClientItemsReturnOrders
where ClientItemsReturnOrderID = U.ClientItemsReturnOrderID)
from [dbo].[tbl_Inv_ClientItemsReturnOrderDetails] U
But I get this error
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.The statement has been terminated.
I want to update column "InventoryReturnReasonID" in table "tbl_Inv_ClientItemsReturnOrderDetails" by value of column "InventoryReturnReasonID" from table "tbl_Inv_ClientItemsReturnOrders"
you can use the query given below for getting better idea about the issue.
SELECT * FROM [dbo].[tbl_Inv_ClientItemsReturnOrderDetails] U
INNER JOIN [dbo].[tbl_Inv_ClientItemsReturnOrders] P ON (P.ClientItemsReturnOrderID = U.ClientItemsReturnOrderID)
we have the option to compile update with join. The query is as follows
UPDATE U
SET U.InventoryReturnReasonID = P.InventoryReturnReasonID
FROM [dbo].[tbl_Inv_ClientItemsReturnOrderDetails] U
INNER JOIN [dbo].[tbl_Inv_ClientItemsReturnOrders] P ON (P.ClientItemsReturnOrderID = U.ClientItemsReturnOrderID)
The error is pretty clear. You can select an arbitrary value using TOP 1:
Update U
set U.InventoryReturnReasonID = (select TOP 1 ro.InventoryReturnReasonID
from tbl_Inv_ClientItemsReturnOrders ro
where ro.ClientItemsReturnOrderID = U.ClientItemsReturnOrderID
)
from [dbo].tbl_Inv_ClientItemsReturnOrderDetails U;
Normally, TOP should have an ORDRER BY. You can include an ORDER BY to specify which of multiple values the update should use.
Note: Using qualified column names (i.e. including a table alias) is always a good idea. It should be mandatory with a correlated subquery because of the potential danger if something goes wrong. For instance, your query would return too many rows if the column ro.ClientItemsReturnOrderID did not exist.
Another approach is to use aggregation:
Update U
set U.InventoryReturnReasonID = (select max(ro.InventoryReturnReasonID)
from tbl_Inv_ClientItemsReturnOrders ro
where ro.ClientItemsReturnOrderID = U.ClientItemsReturnOrderID
)
from [dbo].tbl_Inv_ClientItemsReturnOrderDetails U;

Oracle SQL - How do I update from an Outer Joined Table?

The Problem
I need to write an Update query where my SET references an outer joined table.
I can do this fairly easily with SQL Server but I'm having a heck of a time figuring out the syntax in Oracle as I'm only allow a single table in an update query.
I have written the following Oracle query:
UPDATE SalesExt_tmp tmp
SET slsrep = (SELECT three_dig_rep
FROM dw_sls_rep_conv sls
WHERE sls.aims_rep = tmp.slsrep)
WHERE EXISTS (SELECT three_dig_rep
FROM dw_sls_rep_conv sls
WHERE sls.aims_rep = tmp.slsrep)
AND tmp.sysind = 'AIM';
This takes care of the intersection but I need to deal with values in SalesExt_tmp that do not have equivalent matches in dw_sls_rep_conv (I plan to add a case statement to set null values to a default value). To do this I need to set up dw_sls_rep_conv as an outer joined table. But this is where I get stuck.
SQL Server Example
In SQL Server the solution is a piece of cake as you can have multiple tables in an Update Query:
UPDATE SalesExt_tmp tmp
LEFT JOIN dw_sls_rep_conv sls ON sls.aims_rep = tmp.slsrep
SET tmp.slsrep = sls.three_dig_rep
WHERE tmp.sysind = 'AIM';
But I can't for the life of me figure out how to do this in Oracle. I understand that this query will allow my slsrep field to be set to NULL in some occasions which causes me to fear that this operation may not be allowed.
Questions
1) Firstly is this possible in Oracle? (It's got to be, right?)
2) How do I need to restructure my query to pull this off? I'm guessing my WHERE EXISTS clause needs to go... but I'm still stuck as to where to place my JOIN.
If I understood you correctly, you want to set the value to NULL if there is no match in the dw_sls_rep_conv table? If so, just drop your EXISTS condition and all the rows will be updated:
UPDATE SalesExt_tmp tmp
SET slsrep = (SELECT three_dig_rep
FROM dw_sls_rep_conv sls
WHERE sls.aims_rep = tmp.slsrep)
WHERE tmp.sysind = 'AIM';
If there is a match in the dw_sls_rep_conv table, then the slsrep column will be updated with selected value, otherwise, with NULL.
Have you considered using a subquery in your where clause that performs the outer join as you stated like this:
UPDATE SalesExt_tmp tmp
SET slsrep = (SELECT three_dig_rep
FROM dw_sls_rep_conv sls WHERE sls.aims_rep = tmp.slsrep)
WHERE
tmp.rowid in
(SELECT tmp1.rowid
FROM SalesExt_tmp tmp1,
dw_sls_rep_conv sls
WHERE
tmp1.slsrep = sls.aims_rep (+)
AND tmp1.sysind = 'AIM' );