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!
Related
I have two tables let’s say A & B and would like to update the column of Status in table A with maximum matches from the column Scores in table B by comparing the 'Topics' of two tables.
I am using the script shown here, but it's taking a really long time so I'd appreciate it if somebody could provide an alternative / better and faster option/script
UPDATE tableA
SET status = (SELECT max(scores)
FROM tableB
WHERE tableB.topics = tableA.topics)
Try creating proper indexes for each column involved and you should be fine, e.g:
CREATE INDEX idx_tableb_topics_scores ON tableb (topics,scores);
An alternative to your query is to apply the aggregate function max() in a way that it only has to be executed once, but I doubt it will speed things up:
UPDATE tablea a SET status = j.max_scores
FROM (SELECT a.topics,max(b.scores) AS max_scores
FROM tablea a
JOIN tableb b ON a.topics = b.topics
GROUP BY a.topics) j
WHERE a.topics = j.topics;
For this query:
UPDATE tableA
SET status = (SELECT max(scores)
FROM tableB
WHERE tableB.topics = tableA.topics
);
The only index you need is on tableB(topics, scores).
If you like, you can rewrite this as an aggregation, which looks like this:
UPDATE tableA
SET status = b.max_scores
FROM (SELECT b.topic, MAX(scores) as max_scores
FROM tableB b
GROUP BY b.topic
) b
WHERE b.topic = a.topic;
Note that this is subtly different from your query. If there are topics in A that are not in B, then this will not update those rows. I do not know if that is desirable.
If many rows in A have the same topic, then pre-aggregating could be significantly faster than the correlated subquery.
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.
Hoping someone can be of assistance. I am trying to do an update statement. I have a table that has the columns:
BUS_NBR_SK, BUS_NBR, EFF_DT, ENT_TMPSTP, EXP_DT.
Primary keys are BUS_NBR_SK and BUS_NBR. There is only one table here.
These are inserts into a table and I need to update the EXP_DT on the older records and leave the most recent one alone by using the max(ENT_TMSTP) I was going to just do an update with a SET b.EXP_DT = current_timestamp where EXP_DT IS NULL however that won't work because the most recent record will also be assigned an expire date.
Any ideas how that could work?
I have tried the following but it was updating everything with the max effective date.
UPDATE TABLE b
SET b.EXP_DT = (SELECT MAX(a.EFF_DT)
FROM TABLE A
INNER JOIN TABLE B
ON A.BUS_NBR_SK = B.BUS_NBR_SK
AND A.ENT_TMSTP = B.ENT_TMSTP
AND A.BUS_NBR = B.BUS_NBR)
WHERE EXP_DT IS NULL
and ENT_TMSTP != (select max(c.ENT_TMSTP)
from table C)
Thank you so much!
example of the fields in the table with sample data.
I'm not sure if this will fix your problem, but using a correlated subquery will at least get the set logic correct:
UPDATE table b
SET b.EXP_DT = (SELECT MAX(a.EFF_DT)
FROM TABLE A
WHERE A.BUS_NBR_SK = B.BUS_NBR_SK AND
A.ENT_TMSTP = B.ENT_TMSTP AND
A.BUS_NBR = B.BUS_NBR
)
WHERE b.EXP_DT IS NULL AND
b.ENT_TMSTP <> (SELECT MAX(c.ENT_TMSTP) FROM table C);
I'm not sure if this fixes your overall problem, though.
If you want to update b.EXP_DT with the date at a.EFF_DT for the newest record for a specific key of BUS_NBR_SK, ENT_TMSTP and BUS_NBR you can create a Group by view for A or you can declare it inside the update query as shown below:
UPDATE table b
SET b.EXP_DT = A_Group.Max_EFF
FROM TABLE A INNER JOIN
(SELECT BUS_NBR_SK, ENT_TMSTP, BUS_NBR, MAX(A.EFF) as Max_EFF
FROM B
GROUP BY BUS_NBR_SK, ENT_TMSTP, BUS_NBR) AS A_Group ON
A_Group.BUS_NBR_SK = b.BUS_NBR_SK AND
A_Group.ENT_TMSTP = b.ENT_TMSTP AND
A_Group.BUS_NBR = b.BUS_NBR
WHERE b.EXP_DT IS NULL AND
b.ENT_TMSTP <> (A_Group.Max_EFF);
Hope it helps.
Sergio
I would like to update columns in Table A based on values in Table B. Using below format, but getting syntax error.
update TableA
set
TableA.MOdule_id =TableB.MOdule_id
from TableA
inner join
TableB
on TableA.end_Slot_id =TableB.Slot_Id
where TableA.Slot_Id = 'AAA';
It would be great help, if anyone can help on this.
A quick search for "informix sql update" returns two reference manual pages that describe the syntax for the UPDATE command. Neither one indicates support for the nonstandard FROM clause.
Standard SQL uses a correlated subquery for the purpose. Your query should look something like
update TableA
set MOdule_id =
(select TableB.MOdule_id
from TableB
on TableA.end_Slot_id = Slot_Id)
where Slot_Id = 'AAA'
and exists (
select 1
from TableB
on TableA.end_Slot_id = Slot_Id
and TableA.Slot_Id = 'AAA'
);
The EXISTS clause ensures that only rows that exist in B are applied to A. Without it, any missing rows would be updated to NULL.
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