Update table a from table b where (conditions) - sql

Evening all,
Actually, it's night. About 11pm. My brain is shutting down and I need a bit of help so I can finish and go home :)
I have two tables - table a and table b.
I need to update a field in table a with the value from a field in table b when two other fields match. The tables don't have a unique id for each record :(
Basically, I want to do this:
update a
set importantField =
(select b.importantfield
from b
where a.matchfield = b.matchfield
and a.matchfield2 = b.matchfield2
)
where a.matchfield = b.matchfield
and a.matchfield2 = b.matchfield2
Or at least... I think that's what I want to do...
Can someone help me out, please?

You can do this via a join in the update:
Update a
Set a.importantField = b.importantField
From a Join b
On a.matchfield = b.matchfield
And a.matchfield2 = b.matchfield2

Use:
UPDATE TABLE_A
SET importantField = (SELECT b.importantfield
FROM TABLE_B b
WHERE b.matchfield = matchfield
AND b.matchfield2 = matchfield2)
SQL Server doesn't support table aliases on the table being updated, but the above is a correlated query - those fields without the table alias b attached will serve values from TABLE_A because it doesn't have an alias.
The only issue beyond that is if there are multiple b.importantfield values for records with the matching records to TABLE_A. Use:
UPDATE TABLE_A
SET importantField = (SELECT TOP 1
b.importantfield
FROM TABLE_B b
WHERE b.matchfield = matchfield
AND b.matchfield2 = matchfield2)
..but you should use an ORDER BY as well or you'll get any random b.importantfield value.

Related

update multiple rows with joins

I have this query in postgresql:
select *
from A s
join B m on (s.id=m.id)
where m.key=4 and s.ran=some_input_from_user
This gives me all the rows that I need to update.
I want to set A.value to be 90 for all these rows.
It doesn't look like a standart update query
if I do...
Update A set value=90 where.....
then I can't do the join.
any ideas how to do it?
This is the basic update syntax for PostgreSQL where you are updating based on a join to another table:
update A s
set
value = 90
from B m
where
s.id = m.id and
m.key = 4 and
s.ran = some_input_from_user
The trick is you never use the alias in the lvalue for the set commands. In other words, value = 90 is not s.value = 90. It seems minor, but I'm pretty sure it will prevent your query from working. The rationale is if you are updating table A (alias s) then any fields you are updating are, de-facto, from table A -- no need to alias them, and to allow aliases would almost imply you could update something other than A with this statement, which you cannot.
You can definitely use them in the rvalues, so this would certainly be okay (if it were your desire to update A based on B):
update A s
set
value = m.salary * s.commission
from B m
where
s.id = m.id and
(s.value is null or
s.value != m.salary * s.commission)
Here is the query:
update a set value = 90
where exists (
select 1 from b
where a.id = b.id and b.key=4
and a.ran=some_input_from_user);
The above query will eliminate the requirement of reading table a twice.
Also you can use this query:
update a set value = 90
where a.id in
(select b.id from b
where a.id = b.id and b.key = 4
and a.ran=some_input_from_user);
TRY THIS
UPDATE A
SET A.VALUE = 90
from A
join B m on (A.id=m.id)
where m.key=4 and s.ran=some_input_from_user

Error FROM Clause on update sql (postgres) [duplicate]

Basically, I want to do this:
update vehicles_vehicle v
join shipments_shipment s on v.shipment_id=s.id
set v.price=s.price_per_vehicle;
I'm pretty sure that would work in MySQL (my background), but it doesn't seem to work in postgres. The error I get is:
ERROR: syntax error at or near "join"
LINE 1: update vehicles_vehicle v join shipments_shipment s on v.shi...
^
Surely there's an easy way to do this, but I can't find the proper syntax. So, how would I write this In PostgreSQL?
The UPDATE syntax is:
[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table [ [ AS ] alias ]
SET { column = { expression | DEFAULT } |
( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) } [, ...]
[ FROM from_list ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
In your case I think you want this:
UPDATE vehicles_vehicle AS v
SET price = s.price_per_vehicle
FROM shipments_shipment AS s
WHERE v.shipment_id = s.id
Or if you need to join on two or more tables:
UPDATE table_1 t1
SET foo = 'new_value'
FROM table_2 t2
JOIN table_3 t3 ON t3.id = t2.t3_id
WHERE
t2.id = t1.t2_id
AND t3.bar = True;
The answer of Mark Byers is the optimal in this situation.
Though in more complex situations you can take the select query that returns rowids and calculated values and attach it to the update query like this:
with t as (
-- Any generic query which returns rowid and corresponding calculated values
select t1.id as rowid, f(t2, t2) as calculatedvalue
from table1 as t1
join table2 as t2 on t2.referenceid = t1.id
)
update table1
set value = t.calculatedvalue
from t
where id = t.rowid
This approach lets you develop and test your select query and in two steps convert it to the update query.
So in your case the result query will be:
with t as (
select v.id as rowid, s.price_per_vehicle as calculatedvalue
from vehicles_vehicle v
join shipments_shipment s on v.shipment_id = s.id
)
update vehicles_vehicle
set price = t.calculatedvalue
from t
where id = t.rowid
Note that column aliases are mandatory otherwise PostgreSQL will complain about the ambiguity of the column names.
Let me explain a little more by my example.
Task: correct info, where abiturients (students about to leave secondary school) have submitted applications to university earlier, than they got school certificates (yes, they got certificates earlier, than they were issued (by certificate date specified). So, we will increase application submit date to fit certificate issue date.
Thus. next MySQL-like statement:
UPDATE applications a
JOIN (
SELECT ap.id, ab.certificate_issued_at
FROM abiturients ab
JOIN applications ap
ON ab.id = ap.abiturient_id
WHERE ap.documents_taken_at::date < ab.certificate_issued_at
) b
ON a.id = b.id
SET a.documents_taken_at = b.certificate_issued_at;
Becomes PostgreSQL-like in such a way
UPDATE applications a
SET documents_taken_at = b.certificate_issued_at -- we can reference joined table here
FROM abiturients b -- joined table
WHERE
a.abiturient_id = b.id AND -- JOIN ON clause
a.documents_taken_at::date < b.certificate_issued_at -- Subquery WHERE
As you can see, original subquery JOIN's ON clause have become one of WHERE conditions, which is conjucted by AND with others, which have been moved from subquery with no changes. And there is no more need to JOIN table with itself (as it was in subquery).
For those actually wanting to do a JOIN you can also use:
UPDATE a
SET price = b_alias.unit_price
FROM a AS a_alias
LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
WHERE a_alias.unit_name LIKE 'some_value'
AND a.id = a_alias.id;
You can use the a_alias in the SET section on the right of the equals sign if needed.
The fields on the left of the equals sign don't require a table reference as they are deemed to be from the original "a" table.
For those wanting to do a JOIN that updates ONLY the rows your join returns use:
UPDATE a
SET price = b_alias.unit_price
FROM a AS a_alias
LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
WHERE a_alias.unit_name LIKE 'some_value'
AND a.id = a_alias.id
--the below line is critical for updating ONLY joined rows
AND a.pk_id = a_alias.pk_id;
This was mentioned above but only through a comment..Since it's critical to getting the correct result posting NEW answer that Works
Here we go:
update vehicles_vehicle v
set price=s.price_per_vehicle
from shipments_shipment s
where v.shipment_id=s.id;
Simple as I could make it.
To add something quite important to all the great answers above, when you want to update a join-table, you may have 2 problems:
you cannot use the table you want to update to JOIN another one
Postgres wants a ON clause after the JOIN so you cannot only use where clauses.
This means that basically, the following queries are not valid:
UPDATE join_a_b
SET count = 10
FROM a
JOIN b on b.id = join_a_b.b_id -- Not valid since join_a_b is used here
WHERE a.id = join_a_b.a_id
AND a.name = 'A'
AND b.name = 'B'
UPDATE join_a_b
SET count = 10
FROM a
JOIN b -- Not valid since there is no ON clause
WHERE a.id = join_a_b.a_id
AND b.id = join_a_b.b_id
a.name = 'A'
AND b.name = 'B'
Instead, you must use all the tables in the FROM clause like this:
UPDATE join_a_b
SET count = 10
FROM a, b
WHERE a.id = join_a_b.a_id
AND b.id = join_a_b.b_id
AND a.name = 'A'
AND b.name = 'B'
It might be straightforward for some but I got stuck on this problem wondering what's going on so hopefully, it will help others.
Here's a simple SQL that updates Mid_Name on the Name3 table using the Middle_Name field from Name:
update name3
set mid_name = name.middle_name
from name
where name3.person_id = name.person_id;
The link below has a example that resolve and helps understant better how use update and join with postgres.
UPDATE product
SET net_price = price - price * discount
FROM
product_segment
WHERE
product.segment_id = product_segment.id;
See: http://www.postgresqltutorial.com/postgresql-update-join/
First Table Name: tbl_table1 (tab1).
Second Table Name: tbl_table2 (tab2).
Set the tbl_table1's ac_status column to "INACTIVE"
update common.tbl_table1 as tab1
set ac_status= 'INACTIVE' --tbl_table1's "ac_status"
from common.tbl_table2 as tab2
where tab1.ref_id= '1111111'
and tab2.rel_type= 'CUSTOMER';
To UPDATE one Table using another, in PostGRE SQL / AWS (SQL workbench).
In PostGRE SQL, this is how you need to use joins in UPDATE Query:
UPDATE TABLEA set COLUMN_FROM_TABLEA = COLUMN_FROM_TABLEB FROM TABLEA,TABLEB WHERE FILTER_FROM_TABLEA = FILTER_FROM_TABLEB;
Example:
Update Employees Set Date_Of_Exit = Exit_Date_Recorded , Exit_Flg = 1 From Employees, Employee_Exit_Clearance Where Emp_ID = Exit_Emp_ID
Table A - Employees Columns in Table A - Date_Of_Exit,Emp_ID,Exit_Flg Table B is - Employee_Exit_Clearance Columns in Table B - Exit_Date_Recorded,Exit_Emp_ID
1760 rows affected
Execution time: 29.18s
--goal: update selected columns with join (postgres)--
UPDATE table1 t1
SET column1 = 'data'
FROM table1
RIGHT JOIN table2
ON table2.id = table1.id
WHERE t1.id IN
(SELECT table2.id FROM table2 WHERE table2.column2 = 12345)
The first way is slower than the second way.
First:
DO $$
DECLARE
page int := 10000;
min_id bigint; max_id bigint;
BEGIN
SELECT max(id),min(id) INTO max_id,min_id FROM opportunities;
FOR j IN min_id..max_id BY page LOOP
UPDATE opportunities SET sec_type = 'Unsec'
FROM opportunities AS opp
INNER JOIN accounts AS acc
ON opp.account_id = acc.id
WHERE acc.borrower = true
AND opp.sec_type IS NULL
AND opp.id >= j AND opp.id < j+page;
COMMIT;
END LOOP;
END; $$;
Second:
DO $$
DECLARE
page int := 10000;
min_id bigint; max_id bigint;
BEGIN
SELECT max(id),min(id) INTO max_id,min_id FROM opportunities;
FOR j IN min_id..max_id BY page LOOP
UPDATE opportunities AS opp
SET sec_type = 'Unsec'
FROM accounts AS acc
WHERE opp.account_id = acc.id
AND opp.sec_type IS NULL
AND acc.borrower = true
AND opp.id >= j AND opp.id < j+page;
COMMIT;
END LOOP;
END; $$;
WORKS PERFECT!!!
POSTGRE SQL - UPDATE With a JOIN
BELOW CODE - Check the positioning of columns and IDs as below:
If you place it exactly as below, then only it will work!
---IF you want to update FIRST table
UPDATE table1
SET attribute1 = table2.attribute1
FROM table2
WHERE table2.product_ID = table1.product_ID;
OR
---IF you want to update SECOND table
UPDATE table2
SET attribute1 = table1.attribute1
FROM table1
WHERE table1.product_ID = table2.product_ID;

Update statement in SQL

I am writing an Update trigger and am struggling with the Update statement:
The statement is as below:
UPDATE ARGUS_APP.CMN_REG_REPORTS CARR
SET CARR.DATE_SUBMITTED =
(
SELECT To_Date(M.ACKNOWLEDGMENTHEADER.MESSAGEDATE,'YYYYMMDDHH24MISS') Messagedate
FROM esm_owner.MESSAGES M
WHERE M.ACKNOWLEDGMENTHEADER.MESSAGESENDERIDENTIFIER='PMDA'
)
WHERE CARR.DATE_SUBMITTED =
(
SELECT CARR.DATE_SUBMITTED
FROM esm_owner.safetyreport sr,esm_owner.MESSAGES M,ARGUS_APP.CMN_REG_REPORTS CARR
WHERE sr.report_id=CARR.esm_report_id
AND M.msg_id = sr.msg_id
AND M.ACKNOWLEDGMENTHEADER.MESSAGESENDERIDENTIFIER='PMDA'
)
I get ORA:01427 everytime.
The Table structure is as below:
I have 3 tables
ARGUS_APP.CMN_REG_REPORTS CARR .............having the columns DATE_SUBMITTED(which I want to update) and esm_report_id which joins with the report_id of safety report
ESM_OWNER.SAFETYREPORT SR............having the columns report_id and MSG_ID(joined with the msg_id of the MESSAGES table)
MESSAGES M ..........having the columns MSG_ID and ACKNOWLEDGMENTHEADER.MESSAGESENDERIDENTIFIER
Please help me resolve this.
I'm going to take a wild stab and guess that this is what you are after. They key feature is correlating the subselects with the update (the carr in the subselects refer to the table in the outer statement).
Update
argus_app.cmn_reg_reports carr
set
carr.date_submitted = (
Select
To_Date(m.AcknowledgmentHeader.MessageDate, 'YYYYMMDDHH24MISS') Messagedate
from
esm_owner.Messages m
inner join
esm_owner.SafetyReport sr
on m.msg_id = sr.msg_id
where
carr.esm_report_id = sr.report_id And
m.AcknowledgmentHeader.MessageSenderIdentifier = 'PMDA'
)
Where
Exists (
Select
'x'
From
esm_owner.Messages m
Inner Join
esm_owner.SafetyReport sr
on m.msg_id = sr.msg_id
Where
carr.esm_report_id = sr.report_id and
m.AcknowledgmentHeader.MessageSenderIdentifier = 'PMDA'
)
Here's an example showing the basic principle works:
Example Fiddle
It looks like one of your subqueries is probably returning more than one row of data. You could perhaps check this by running each on its own.
If you want the update to apply to them all, change the
... = (SELECT...
to
... IN (SELECT ...

SQLite inner join - update using values from another table

This is quite easy and has been asked multiple times but I can't get it to work.
The SQL query I think should work is:
UPDATE table2
SET dst.a = dst.a + src.a,
dst.b = dst.b + src.b,
dst.c = dst.c + src.c,
dst.d = dst.d + src.d,
dst.e = dst.e + src.e
FROM table2 AS dst
INNER JOIN table1 AS src
ON dst.f = src.f
Using the update statement it is not possible because in sqlite joins in an update statement are not supported. See docs:
update statement
If you only wanted to update a single column to a static value, you could use a subquery in the update statement correctly. See this example: How do I make an UPDATE while joining tables on SQLite?
Now in your example, making an assumption that there is a unique key on "column f" - a workaround/solution I have come up with is using the replace statement:
replace into table2
(a, b, c, d, e, f, g)
select src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f
I also added an extra column to table2 "column g" to show how you'd "update" only some of the columns with this method.
One other thing to be cautious about is if you use "PRAGMA foreign_keys = ON;" it's possible to have issues with this as the row is effectively deleted and inserted.
I came up with an alternative technique using a TRIGGER and "reversing" the direction of the update, albeit at the cost of a dummy field in the source table.
In general terms, you have a Master table and an Updates table. You want to update some/all fields of records in Master from the corresponding fields in Updates linked by a key field Key.
Instead of UPDATE Master SET ... FROM Master INNER JOIN Updates ON Mater.Key = Updates.Key you do the following:
Add a dummy field TriggerField to the Updates table to act as the focus of the trigger.
Create a trigger on this field:
CREATE TRIGGER UpdateTrigger AFTER UPDATE OF TriggerField ON Updates
BEGIN
UPDATE Master SET
Field1 = OLD.Field1,
Field2 = OLD.Field2,
...
WHERE Master.Key = OLD.Key
END;
Launch the update process with the following:
UPDATE Updates SET TriggerField = NULL ;
Notes
The dummy field is merely an anchor for the trigger so that any other UPDATE Updates SET ... won't trigger the update into Master. If you only ever INSERT into Updates then you don't need it (and can remove the OF TriggerField clause when creating the trigger).
From some rough-and-ready timings, this seems to work about the same speed as REPLACE INTO but avoids the feels-slightly-wrong technique of removing and adding rows. It is also simpler if you are only updating a few fields in Master as you only list the ones you want to change.
It is orders of magnitude faster than the other alternative I've seen to UPDATE ... FROM which is:
UPDATE Master SET
Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
...
;
Updating six fields over 1700 records was roughly 0.05s for Tony and my methods but 2.50s for the UPDATE ... ( SELECT... ) method.
AFTER UPDATE triggers on Master seem to fire as expected.
As Tony says, the solution is the replace into way but you can use the sqlite hidden field rowid to simulate full update with join like:
replace into table2
(rowid,a, b, c, d, e, f, g)
select dest.rowid,src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f
With this you recreate full rows if you don't have primary key for the replace or as standard method to do the updates with joins.
SQLITE does not support UPDATE with INNER JOIN nor do several other DB's. Inner Joins are nice and simple however it can be accomplished using just a UPDATE and a subquery select. By using a where clause and the 'IN' with a subquery and a additional subquery for the 'SET' the same result can always be accomplished. Below is how it's done.
UPDATE table2
SET a = a + (select a from table1 where table1.f = table2.f),
b = b + (select b from table1 where table1.f = table2.f),
c = c + (select c from table1 where table1.f = table2.f),
d = d + (select d from table1 where table1.f = table2.f),
e = e + (select e from table1 where table1.f = table2.f)
WHERE RowId IN (Select table2.RowId from table1 where table1.f = table2.f)
Use below query:
UPDATE table2
SET a = Z.a,
b = Z.b,
c = Z.c,
d = Z.d,
e = Z.e
FROM (SELECT dst.id,
dst.a + src.a AS a,
dst.b + src.b AS b,
dst.c + src.c AS c,
dst.d + src.d AS d,
dst.e + src.e AS e
FROM table2 AS dst
INNER JOIN table1 AS src ON dst.f = src.f
)Z
WHERE table2.id = z.id

UPDATE row when matching row exists in another table

I need to update a field on a table to be true only if a matching row exists in another table, for all the rows where the column is currently null in the main table.
This is a description of what I want to achieve:
UPDATE [LenqReloaded].[dbo].[Enquiry] A
SET [ResponseLetterSent] = 1
WHERE [ResponseLetterSent] IS NULL
AND EXISTS
(
SELECT * FROM [LenqReloaded].[dbo].[Attachment] B
WHERE A.[EnquiryID] = B.[EnquiryID]
)
This isn't syntactically correct.
I can't code it via an IF EXISTS... statement because I don't have the [EnquiryID] without reading the data from the table.
How should I format my UPDATE statement?
You weren't far off...
UPDATE A
SET A.[ResponseLetterSent] = 1
FROM [LenqReloaded].[dbo].[Enquiry] A
WHERE A.[ResponseLetterSent] IS NULL
AND EXISTS ( SELECT * FROM [LenqReloaded].[dbo].[Attachment] B WHERE A.[EnquiryID] = B.[EnquiryID] )
You need to use a join in your update:
UPDATE [LenqReloaded].[dbo].[Enquiry] SET [ResponseLetterSent] = 1
FROM [LenqReloaded].[dbo].[Enquiry] A
join [LenqReloaded].[dbo].[Attachment] B on A.[EnquiryID] = B.[EnquiryID]
WHERE A.[ResponseLetterSent] IS NULL
This seems counterintuitive, but you need to establish a table alias in a From clause but use that alias in the Update Clause...
Update E Set
ResponseLetterSent = 1
From LenqReloaded.dbo.Enquiry E
Where ResponseLetterSent Is Null
And Exists (Select * From LenqReloaded.dbo.Attachment
Where EnquiryID = E.EnquiryID)
The thing you are missing is the 'from' clause, which is a t-sql extension - it is the only way to assign an alias to the updated table
update [lenqreloaded].[dbo].[enquiry]
set [responselettersent] = 1
from [lenqreloaded].[dbo].[enquiry] a
where [responselettersent] is null
and exists (
select *
from [lenqreloaded].[dbo].[attachment] b
where a.[enquiryid] = b.[enquiryid]
)