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.
Related
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.
I have a destination table that needs to be updated with the values that match from my source. I would like my destination to have the same CarValue as my source table would have. I have came up with the query above to pull the records that do not match my source and I want to use this to update my destination table values. Please provide examples of how to accomplish this.
select
s.*
,t.*
from SourceTable as s
full outer join DestinationTable as t
on s.CarNo = t.CarNo and s.CarName = t.CarName
where s.CarValue <> t.Carvalue
You do not need a full join. So:
update t
set carvalue = s.carvalue
from DestinationTable t join
SourceTable s
on s.CarNo = t.CarNo and s.CarName = t.CarName
where s.CarValue <> t.Carvalue;
This does not update non-matching rows. My guess is that you want to leave those alone. If you do want to update them, use a left join and remove the where clause.
You can update by using the current join statement
update t
set t.CarValue = s.Carvalue
from DestinationTable as t
full outer join SourceTable as s
on s.CarNo = t.CarNo and s.CarName = t.CarName
where s.Carvalue<>coalesce(t.Carvalue,'xYz');
coalesce() is added for the probability of existence of null values within the DestinationTable, assuming a car value never would be xYz.
Demo
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
I have two tables. I want to update one with another.
I have written two queries to show you the result. Here are my two queries
select PrjTermsID,InstNo,InstDesc,BlockID from ProjectPaymentTerms where BlockID=1
select PlotBookingID,InstNo,InstDesc,PrjTermsID from PlotPaymentTerms where PlotBookingID in
( select PlotBookingID from PlotBooking where PlotID in ( select PlotID from PlotMaster where AppartmentBlock=1))
and see the image for results
First table has 1 to 13 records with InstNo and second table has each PlotBookingID has 13 records.(Each plot will have 13(all) payment terms right?). Now I want to update the second table PlotPaymentTerms with first table autogenerated Id. IF I try with Inner join it is giving more results. How can I write update query to update the second table?
update ppt
set ppt.PrjTermsID = pp.PrjTermsID
from PlotPaymentTerms ppt
inner join ProjectPaymentTerms pp on ppt.InstNo = pp.InstNo and ppt.BlockID = 1
inner join PlotBooking pb on ppt.PlotBookingID = pb.PlotBookingID
inner join PlotMaster pm on pb.PlotID = pm.PlotID
where pm.AppartmentBlock = 1
please check this.
I don't think it is the right way to do. Anyways it works for me.
update ppt set ppt.PrjTermsID = pp.PrjTermsID from PlotPaymentTerms ppt
inner join ProjectPaymentTerms pp on ppt.InstNo = pp.InstNo and pp.BlockID=1
and ppt.PlotBookingID in(select PlotBookingID from PlotBooking where PlotID in ( select PlotID from PlotMaster where AppartmentBlock=1))
Thnaks to #Mukund
I have a very suspicious feeling that this update trigger is updating ALL rows on the target, not just those that satisfy the "update(shape)" test. Performance was fine 'till I added the second operation. A single spatial join occurs much faster, and this is a not a spatial index issue, as well, there are only a few records in this dataset.
ALTER TRIGGER [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
ON [dbo].[GRSM_WETLANDS_POINT]
after update
AS
BEGIN
SET NOCOUNT ON;
if UPDATE (shape)
update GRSM_WETLANDS_Point
set X_Coord =CASE WHEN u.shape.STDimension() = 2 THEN u.shape.STCentroid().STX ELSE u.shape.STEnvelope().STCentroid().STX END,
Y_Coord =CASE WHEN u.shape.STDimension() = 2 THEN u.shape.STCentroid().STY ELSE u.shape.STEnvelope().STCentroid().STY END
from inserted i
inner join GRSM_WETLANDS_POint u on i.GIS_Location_ID = u.GIS_Location_ID;
--second spatial operation
update GRSM_WETLANDS_Point
set QuadName = grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES.name
FROM GRSM_WETLANDS_POint i
inner join grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES
on i.GIS_Location_ID = i.GIS_Location_ID
WHERE (USGS_24K_TOPOMAP_BOUNDARIES.Shape.STContains(i.SHAPE) = 1) ;
end
Is my suspicion right?
Upated: Based on suggestion from Aaron...solves the fire on all rows issue.
update GRSM_WETLANDS_Point
set QuadName = grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES.name
FROM inserted i inner join GRSM_WETLANDS_POint u on i.GIS_Location_ID = u.GIS_Location_ID
left outer join grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES
on i.GIS_Location_ID = i.GIS_Location_ID
WHERE (USGS_24K_TOPOMAP_BOUNDARIES.Shape.STContains(i.SHAPE) = 1);
If Shape can't be NULL, a better way to see if it has changed is to check if the values in inserted and deleted are different. For example:
IF EXISTS
(
SELECT 1 FROM inserted AS i
INNER JOIN deleted AS d
ON i.GIS_Location_ID = d.GIS_Location_ID
WHERE i.Shape.STEquals(d.Shape) = 0
)
BEGIN
...
END
If Shape is nullable then you just have to add more conditions there to check, e.g.
WHERE
(
(i.Shape IS NULL AND d.Shape IS NOT NULL
OR (i.Shape IS NOT NULL AND d.Shape IS NULL)
OR (i.Shape.STEquals(d.Shape) = 0)
)
(You might not care if Shape has been updated to NULL, I'm just illustrating how to test for that case.)
Since the operation can occur on multiple rows, and this condition will only identify that at least one such update has occurred (but not that ALL rows meet the condition), it may be better to have your operations include similar criteria in the WHERE clause. In fact I think you can perform both updates in a single operation, e.g.
ALTER TRIGGER [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
ON [dbo].[GRSM_WETLANDS_POINT]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE p SET
X_Coord = CASE WHEN i.shape.STDimension() = 2
THEN i.shape.STCentroid().STX
ELSE i.shape.STEnvelope().STCentroid().STX
END,
Y_Coord = CASE WHEN i.shape.STDimension() = 2
THEN i.shape.STCentroid().STY
ELSE i.shape.STEnvelope().STCentroid().STY
END,
QuadName = COALESCE(b.name, p.QuadName)
FROM
dbo.GRSM_WETLANDS_Point AS p
INNER JOIN
inserted AS i
ON i.GIS_Location_ID = p.GIS_Location_ID
LEFT OUTER JOIN grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES AS b
ON b.Shape.STContains(i.Shape) = 1
WHERE EXISTS
(
SELECT 1 FROM inserted AS i2
INNER JOIN deleted AS d
ON i2.GIS_Location_ID = d.GIS_Location_ID
WHERE i2.GIS_Location_ID = i.GIS_Location_ID
AND i2.Shape.STEquals(d.Shape) = 0
-- ...and NULL handling if necessary
);
END
GO
In general, you seem to be having a lot of troubles implementing triggers, and make a lot of guesses about how the syntax should work. Have you considered forcing data updates to occur via stored procedures, where you can control all of this business logic but eliminate the complexity that the inserted and deleted pseudo tables add?
if UPDATE (shape) will fire even if the values don't change, if the column is present in the update statement it will fire
And you are not joining with INSERTED in your second update