I want to update a flag in all the child tables based on the id which is a primary key in master table. I want to do it in single query how can I do it??
Oracle does not support multi-table update statements. If you want a single statement then use PL/SQL to wrap multiple SQL single-table update statements:
DECLARE
v_id MAIN_TABLE.ID%TYPE := 1;
BEGIN
UPDATE child_table1
SET flag = 1
WHERE id = v_id;
UPDATE child_table2
SET flag = 1
WHERE id = v_id;
UPDATE child_table2
SET flag = 1
WHERE id = v_id;
END;
/
UPDATE main
JOIN slave1 USING (id)
JOIN slave2 USING (id)
...
SET slave1.flag = 1,
slave2.flag = 1,
...
WHERE main.id IN ( {ids list} )
...
Use inner join with sub query may helpful
Example:
UPDATE Students
SET flag = true
WHERE id in (SELECT student.id from Students
INNER JOIN Classes
on students.classId = classes.id
);
Related
Attempting to update a table I have created with null values from another table I have created in PL/SQL:
I was able to utilize the below update in SQL Server but am running into issues within PL/SQL (dont ask why I am running it in both)
Overall_Inventory = Table created with some populated values and some null valuse; this is the table requiring updates to those null values
task_table = Table also created, but contains value needing to be updated into T1
update dbh.overall_inventory
set dbh.overall_inventory.case_due_date = tsk.TASK_ACTION_TIMESTAMP
from dbh.overall_inventory,
(SELECT tsk.INQ_KEY,
min(tsk.TASK_ACTION_TIMESTAMP) as TASK_ACTION_TIMESTAMP
FROM dbh.task_table tsk
inner join dbh.overall_inventory Inv
on tsk.INQ_KEY = inv.inq_key
where tsk.ACTION_CD = '324'
group by tsk.INQ_KEY
) tsk
where tsk.INQ_KEY = dbh.overall_inventory.inq_key`
Oracle doesn't support from clause in the update statement. In this situation merge statement can be used.
merge into overall_inventory oi
using (select tsk.inq_key,
min(tsk.task_action_timestamp) as task_action_timestamp
from task_table tsk
join overall_inventory Inv
on tsk.inq_key = inv.inq_key
where tsk.action_cd = '324'
group by tsk.inq_key) tsk
on (tsk.inq_key = oi.inq_key )
when matched then
update
set case_due_date = tsk.task_action_timestamp
where case_due_date is null -- as I understood only NULL values
-- need to be updated
Note: Not tested because no sample data and desired result were provided.
I think you're looking for update over a select:
UPDATE (
SELECT product_id, category_id
FROM product) st
SET st.category_id = 5
WHERE st.category_id = 4;
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;
I'm trying to migrate some tables into an existing table, I need to perform the updates only where DET_ATTACHMENT_ID equals DET_ATTACHMENT.ID, here's the query I have so far.
UPDATE DET_ATTACHMENT
SET attachment_type = 'LAB', -- being added by the query, to replace the table difference
payer_criteria_id = (
SELECT PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT
WHERE DET_LAB_ATTACHMENT.DET_ATTACHMENT_ID = DET_ATTACHMENT.ID)
WHERE exists(
SELECT DET_ATTACHMENT_ID
FROM DET_ATTACHMENT
JOIN DET_LAB_ATTACHMENT ON (ID = DET_ATTACHMENT_ID)
WHERE DET_ATTACHMENT_ID = DET_ATTACHMENT.ID
the problem with the existing query is that it's setting every row to have an attachment_type of "LAB", and nulling out the payer_criteria_id where it didn't match. What am I doing wrong?
The problem might be that your exists(...) predicate always evaluates to true, thus making the update run for all rows of det_attachment. Try it this way:
UPDATE DET_ATTACHMENT X
SET X.attachment_type = 'LAB',
X.payer_criteria_id = (
SELECT C.PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT C
WHERE C.DET_ATTACHMENT_ID = X.ID
)
WHERE
exists(
SELECT 1
FROM DET_ATTACHMENT A
JOIN DET_LAB_ATTACHMENT B
ON B.DET_ATTACHMENT_ID = A.ID
where B.det_attachment_id = X.id
)
;
How would you update data in multiple tables using a single query?
MySQL Example
The equivalent code in MySQL:
UPDATE party p
LEFT JOIN party_name n ON p.party_id = n.party_id
LEFT JOIN party_details d ON p.party_id = d.party_id
LEFT JOIN incident_participant ip ON ip.party_id = p.party_id
LEFT JOIN incident i ON ip.incident_id = i.incident_id
SET
p.employee_id = NULL,
c.em_address = 'x#x.org',
c.ad_postal = 'x',
n.first_name = 'x',
n.last_name = 'x'
WHERE
i.confidential_dt IS NOT NULL
What would be the same statement using Oracle 11g?
Thank you!
RTFM
It seems a single query is insufficient when using Oracle:
http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_108a.htm#2067717
/** XXX CODING HORROR... */
Depending on your needs, you could use an updateable view. You create a view of your base tables and add an "instead of" trigger to this view and you update the view directly.
Some example tables:
create table party (
party_id integer,
employee_id integer
);
create table party_name (
party_id integer,
first_name varchar2(120 char),
last_name varchar2(120 char)
);
insert into party values (1,1000);
insert into party values (2,2000);
insert into party values (3,3000);
insert into party_name values (1,'Kipper','Family');
insert into party_name values (2,'Biff','Family');
insert into party_name values (3,'Chip','Family');
commit;
select * from party_v;
PARTY_ID EMPLOYEE_ID FIRST_NAME LAST_NAME
1 1000 Kipper Family
2 2000 Biff Family
3 3000 Chip Family
... then create an updateable view
create or replace view party_v
as
select
p.party_id,
p.employee_id,
n.first_name,
n.last_name
from
party p left join party_name n on p.party_id = n.party_id;
create or replace trigger trg_party_update
instead of update on party_v
for each row
declare
begin
--
update party
set
party_id = :new.party_id,
employee_id = :new.employee_id
where
party_id = :old.party_id;
--
update party_name
set
party_id = :new.party_id,
first_name = :new.first_name,
last_name = :new.last_name
where
party_id = :old.party_id;
--
end;
/
You can now update the view directly...
update party_v
set
employee_id = 42,
last_name = 'Oxford'
where
party_id = 1;
select * from party_v;
PARTY_ID EMPLOYEE_ID FIRST_NAME LAST_NAME
1 42 Kipper Oxford
2 2000 Biff Family
3 3000 Chip Family
I was having the same problem I couldn't find a easy way to do this in Oracle.
Look here:
Oracle Update Statements for more info.
You could use Oracle MERGE statement to do this. It is a bulk update-or-insert kind of statement based on joining the target table with an inline view.
MERGE INTO bonuses D
USING (
SELECT employee_id, salary, department_id FROM employees
WHERE department_id = 80
) S ON (D.employee_id = S.employee_id)
WHEN MATCHED THEN
UPDATE SET D.bonus = D.bonus + S.salary*.01
WHEN NOT MATCHED THEN
INSERT (D.employee_id, D.bonus)
VALUES (S.employee_id, S.salary*0.1);
if you do not need the insert part, you just omit the last 3 lines above.
In some cases it's possible to use PL/SQL to achieve this. In my case I searched for matching rows in two tables by some criteria, then updated each row in a loop.
Something like this:
begin
for r in (
select t1.id as t1_id, t2.id as t2_id
from t1, t2
where ...
) loop
update t1
set ...
where t1.id = r.t1_id;
update t2
set ...
where t2.id = r.t2_id;
end loop;
end;
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]
)