I have created a stored procedure where I want to update my master table columns from relevant table.
So below is my SP
CREATE OR REPLACE PROCEDURE UPD_RRSOC_MST_COLUMNS AS
BEGIN
MERGE
INTO TBL_RRSOC_STORE_INFO trg
USING (
SELECT t1.SLP_STATE_HEAD, T2.STATE_HEAD_NAME
FROM TBL_RRSOC_STORE_INFO t1
JOIN TBL_STATE_HEAD_INFO t2
ON TBL_RRSOC_STORE_INFO.SLP_STATE_HEAD = TBL_STATE_HEAD_INFO.STATE_HEAD_NAME
-- WHERE TBL_RRSOC_STORE_INFO.UPDATETYPE='blah'
) src
ON (trg.RRSOC_ID = t2.ID)
WHEN MATCHED THEN UPDATE
SET TBL_RRSOC_STORE_INFO.SLP_STATE_HEAD = STATE_HEAD_NAME;
NULL;
END UPD_RRSOC_MST_COLUMNS;
but I am getting error as
Error(10,55): PL/SQL: ORA-00904: "TBL_STATE_HEAD_INFO"."STATE_HEAD_NAME": invalid identifier
How can I create the procedure?
Update
MERGE INTO TBL_RRSOC_STORE_INFO trg
USING (
SELECT t1.SLP_STATE_HEAD,
T2.STATE_HEAD_NAME,
t2.id,
t2.STATE_MOB_NUM
FROM TBL_RRSOC_STORE_INFO t1
JOIN TBL_STATE_HEAD_INFO t2
ON t1.SLP_STATE_HEAD = t2.STATE_HEAD_NAME
) src
ON (trg.RRSOC_ID = src.ID)
WHEN MATCHED THEN UPDATE
SET SLP_STATE_HEAD = src.STATE_HEAD_NAME,
SLP_STATE_HEAD_NO = src.STATE_MOB_NUM;
Use the aliases in the join condition rather than the full table names:
SELECT t1.SLP_STATE_HEAD, T2.STATE_HEAD_NAME
FROM TBL_RRSOC_STORE_INFO t1
JOIN TBL_STATE_HEAD_INFO t2
ON t1.SLP_STATE_HEAD = t2.STATE_HEAD_NAME
Then:
MERGE
INTO TBL_RRSOC_STORE_INFO trg
USING (...) src
ON (trg.RRSOC_ID = t2.ID)
Will fail as you do not have an alias in the MERGE scope called t2 you have the aliases trg and src and src does not have an id column as it is not one of the columns you are SELECTing.
Then:
WHEN MATCHED THEN UPDATE
SET SLP_STATE_HEAD = src.STATE_HEAD_NAME;
You do not need an alias for the table being updated (it can only be trg) but you probably want an alias on the column you are updating from.
Which would give you something like:
MERGE INTO TBL_RRSOC_STORE_INFO trg
USING (
SELECT t1.SLP_STATE_HEAD,
T2.STATE_HEAD_NAME,
t2.id
FROM TBL_RRSOC_STORE_INFO t1
JOIN TBL_STATE_HEAD_INFO t2
ON t1.SLP_STATE_HEAD = t2.STATE_HEAD_NAME
) src
ON (trg.RRSOC_ID = src.ID)
WHEN MATCHED THEN UPDATE
SET SLP_STATE_HEAD = src.STATE_HEAD_NAME;
Related
I have a query which works fine in MySQL, but when I run it on Oracle I get the following error:
SQL Error: ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
The query is:
UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';
That syntax isn't valid in Oracle. You can do this:
UPDATE table1 SET table1.value = (SELECT table2.CODE
FROM table2
WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
FROM table2
WHERE table1.value = table2.DESC);
Or you might be able to do this:
UPDATE
(SELECT table1.value as OLD, table2.CODE as NEW
FROM table1
INNER JOIN table2
ON table1.value = table2.DESC
WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW
It depends if the inline view is considered updateable by Oracle
( To be updatable for the second statement depends on some rules listed
here ).
Use this:
MERGE
INTO table1 trg
USING (
SELECT t1.rowid AS rid, t2.code
FROM table1 t1
JOIN table2 t2
ON table1.value = table2.DESC
WHERE table1.UPDATETYPE='blah'
) src
ON (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
SET trg.value = code;
MERGE with WHERE clause:
MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;
You need the WHERE clause because columns referenced in the ON clause cannot be updated.
Do not use some of the answers above.
Some suggest the use of nested SELECT, don't do that, it is excruciatingly slow. If you have lots of records to update, use join, so something like:
update (select bonus
from employee_bonus b
inner join employees e on b.employee_id = e.employee_id
where e.bonus_eligible = 'N') t
set t.bonus = 0;
See this link for more details.
http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx.
Also, ensure that there are primary keys on all the tables you are joining.
UPDATE ( SELECT t1.value, t2.CODE
FROM table1 t1
INNER JOIN table2 t2 ON t1.Value = t2.DESC
WHERE t1.UPDATETYPE='blah')
SET t1.Value= t2.CODE
As indicated here, the general syntax for the first solution proposed by Tony Andrews is :
update some_table s
set (s.col1, s.col2) = (select x.col1, x.col2
from other_table x
where x.key_value = s.key_value
)
where exists (select 1
from other_table x
where x.key_value = s.key_value
)
I think this is interesting especially if you want update more than one field.
It works fine oracle
merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary
This following syntax works for me.
UPDATE
(SELECT A.utl_id,
b.utl1_id
FROM trb_pi_joint A
JOIN trb_tpr B
ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
)
SET utl_id=utl1_id;
Using description instead of desc for table2,
update
table1
set
value = (select code from table2 where description = table1.value)
where
exists (select 1 from table2 where description = table1.value)
and
table1.updatetype = 'blah'
;
UPDATE table1 t1
SET t1.value =
(select t2.CODE from table2 t2
where t1.value = t2.DESC)
WHERE t1.UPDATETYPE='blah';
UPDATE (SELECT T.FIELD A, S.FIELD B
FROM TABLE_T T INNER JOIN TABLE_S S
ON T.ID = S.ID)
SET B = A;
A and B are alias fields, you do not need to point the table.
UPDATE IP_ADMISSION_REQUEST ip1
SET IP1.WRIST_BAND_PRINT_STATUS=0
WHERE IP1.IP_ADM_REQ_ID =
(SELECT IP.IP_ADM_REQ_ID
FROM IP_ADMISSION_REQUEST ip
INNER JOIN VISIT v
ON ip.ip_visit_id=v.visit_id
AND v.pat_id =3702
); `enter code here`
Just as a matter of completeness, and because we're talking Oracle, this could do it as well:
declare
begin
for sel in (
select table2.code, table2.desc
from table1
join table2 on table1.value = table2.desc
where table1.updatetype = 'blah'
) loop
update table1
set table1.value = sel.code
where table1.updatetype = 'blah' and table1.value = sel.desc;
end loop;
end;
/
Oracle base has a good run down on this.
https://oracle-base.com/articles/misc/updates-based-on-queries
From this link - I used a modification of the above query which did not work for me (the answer from mathguy which uses rowid)
MERGE /*+ APPEND PARALLEL(8) */ INTO dest_table tt
USING source_table st
ON (tt.identifier = st.identifier)
WHEN MATCHED THEN
UPDATE SET tt.number = st.number;
Here I have two tables: source and dest. They both have a varchar field in common and I am adding the source identify field (PK) into the dest table.
update table1 a
set a.col1='Y'
where exists(select 1
from table2 b
where a.col1=b.col1
and a.col2=b.col2
)
I have a query which works fine in MySQL, but when I run it on Oracle I get the following error:
SQL Error: ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
The query is:
UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';
That syntax isn't valid in Oracle. You can do this:
UPDATE table1 SET table1.value = (SELECT table2.CODE
FROM table2
WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
FROM table2
WHERE table1.value = table2.DESC);
Or you might be able to do this:
UPDATE
(SELECT table1.value as OLD, table2.CODE as NEW
FROM table1
INNER JOIN table2
ON table1.value = table2.DESC
WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW
It depends if the inline view is considered updateable by Oracle
( To be updatable for the second statement depends on some rules listed
here ).
Use this:
MERGE
INTO table1 trg
USING (
SELECT t1.rowid AS rid, t2.code
FROM table1 t1
JOIN table2 t2
ON table1.value = table2.DESC
WHERE table1.UPDATETYPE='blah'
) src
ON (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
SET trg.value = code;
MERGE with WHERE clause:
MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;
You need the WHERE clause because columns referenced in the ON clause cannot be updated.
Do not use some of the answers above.
Some suggest the use of nested SELECT, don't do that, it is excruciatingly slow. If you have lots of records to update, use join, so something like:
update (select bonus
from employee_bonus b
inner join employees e on b.employee_id = e.employee_id
where e.bonus_eligible = 'N') t
set t.bonus = 0;
See this link for more details.
http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx.
Also, ensure that there are primary keys on all the tables you are joining.
UPDATE ( SELECT t1.value, t2.CODE
FROM table1 t1
INNER JOIN table2 t2 ON t1.Value = t2.DESC
WHERE t1.UPDATETYPE='blah')
SET t1.Value= t2.CODE
As indicated here, the general syntax for the first solution proposed by Tony Andrews is :
update some_table s
set (s.col1, s.col2) = (select x.col1, x.col2
from other_table x
where x.key_value = s.key_value
)
where exists (select 1
from other_table x
where x.key_value = s.key_value
)
I think this is interesting especially if you want update more than one field.
It works fine oracle
merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary
This following syntax works for me.
UPDATE
(SELECT A.utl_id,
b.utl1_id
FROM trb_pi_joint A
JOIN trb_tpr B
ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
)
SET utl_id=utl1_id;
Using description instead of desc for table2,
update
table1
set
value = (select code from table2 where description = table1.value)
where
exists (select 1 from table2 where description = table1.value)
and
table1.updatetype = 'blah'
;
UPDATE table1 t1
SET t1.value =
(select t2.CODE from table2 t2
where t1.value = t2.DESC)
WHERE t1.UPDATETYPE='blah';
UPDATE (SELECT T.FIELD A, S.FIELD B
FROM TABLE_T T INNER JOIN TABLE_S S
ON T.ID = S.ID)
SET B = A;
A and B are alias fields, you do not need to point the table.
UPDATE IP_ADMISSION_REQUEST ip1
SET IP1.WRIST_BAND_PRINT_STATUS=0
WHERE IP1.IP_ADM_REQ_ID =
(SELECT IP.IP_ADM_REQ_ID
FROM IP_ADMISSION_REQUEST ip
INNER JOIN VISIT v
ON ip.ip_visit_id=v.visit_id
AND v.pat_id =3702
); `enter code here`
Just as a matter of completeness, and because we're talking Oracle, this could do it as well:
declare
begin
for sel in (
select table2.code, table2.desc
from table1
join table2 on table1.value = table2.desc
where table1.updatetype = 'blah'
) loop
update table1
set table1.value = sel.code
where table1.updatetype = 'blah' and table1.value = sel.desc;
end loop;
end;
/
Oracle base has a good run down on this.
https://oracle-base.com/articles/misc/updates-based-on-queries
From this link - I used a modification of the above query which did not work for me (the answer from mathguy which uses rowid)
MERGE /*+ APPEND PARALLEL(8) */ INTO dest_table tt
USING source_table st
ON (tt.identifier = st.identifier)
WHEN MATCHED THEN
UPDATE SET tt.number = st.number;
Here I have two tables: source and dest. They both have a varchar field in common and I am adding the source identify field (PK) into the dest table.
update table1 a
set a.col1='Y'
where exists(select 1
from table2 b
where a.col1=b.col1
and a.col2=b.col2
)
I have a query which works fine in MySQL, but when I run it on Oracle I get the following error:
SQL Error: ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
The query is:
UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';
That syntax isn't valid in Oracle. You can do this:
UPDATE table1 SET table1.value = (SELECT table2.CODE
FROM table2
WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
FROM table2
WHERE table1.value = table2.DESC);
Or you might be able to do this:
UPDATE
(SELECT table1.value as OLD, table2.CODE as NEW
FROM table1
INNER JOIN table2
ON table1.value = table2.DESC
WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW
It depends if the inline view is considered updateable by Oracle
( To be updatable for the second statement depends on some rules listed
here ).
Use this:
MERGE
INTO table1 trg
USING (
SELECT t1.rowid AS rid, t2.code
FROM table1 t1
JOIN table2 t2
ON table1.value = table2.DESC
WHERE table1.UPDATETYPE='blah'
) src
ON (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
SET trg.value = code;
MERGE with WHERE clause:
MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;
You need the WHERE clause because columns referenced in the ON clause cannot be updated.
Do not use some of the answers above.
Some suggest the use of nested SELECT, don't do that, it is excruciatingly slow. If you have lots of records to update, use join, so something like:
update (select bonus
from employee_bonus b
inner join employees e on b.employee_id = e.employee_id
where e.bonus_eligible = 'N') t
set t.bonus = 0;
See this link for more details.
http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx.
Also, ensure that there are primary keys on all the tables you are joining.
UPDATE ( SELECT t1.value, t2.CODE
FROM table1 t1
INNER JOIN table2 t2 ON t1.Value = t2.DESC
WHERE t1.UPDATETYPE='blah')
SET t1.Value= t2.CODE
As indicated here, the general syntax for the first solution proposed by Tony Andrews is :
update some_table s
set (s.col1, s.col2) = (select x.col1, x.col2
from other_table x
where x.key_value = s.key_value
)
where exists (select 1
from other_table x
where x.key_value = s.key_value
)
I think this is interesting especially if you want update more than one field.
It works fine oracle
merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary
This following syntax works for me.
UPDATE
(SELECT A.utl_id,
b.utl1_id
FROM trb_pi_joint A
JOIN trb_tpr B
ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
)
SET utl_id=utl1_id;
Using description instead of desc for table2,
update
table1
set
value = (select code from table2 where description = table1.value)
where
exists (select 1 from table2 where description = table1.value)
and
table1.updatetype = 'blah'
;
UPDATE table1 t1
SET t1.value =
(select t2.CODE from table2 t2
where t1.value = t2.DESC)
WHERE t1.UPDATETYPE='blah';
UPDATE (SELECT T.FIELD A, S.FIELD B
FROM TABLE_T T INNER JOIN TABLE_S S
ON T.ID = S.ID)
SET B = A;
A and B are alias fields, you do not need to point the table.
UPDATE IP_ADMISSION_REQUEST ip1
SET IP1.WRIST_BAND_PRINT_STATUS=0
WHERE IP1.IP_ADM_REQ_ID =
(SELECT IP.IP_ADM_REQ_ID
FROM IP_ADMISSION_REQUEST ip
INNER JOIN VISIT v
ON ip.ip_visit_id=v.visit_id
AND v.pat_id =3702
); `enter code here`
Just as a matter of completeness, and because we're talking Oracle, this could do it as well:
declare
begin
for sel in (
select table2.code, table2.desc
from table1
join table2 on table1.value = table2.desc
where table1.updatetype = 'blah'
) loop
update table1
set table1.value = sel.code
where table1.updatetype = 'blah' and table1.value = sel.desc;
end loop;
end;
/
Oracle base has a good run down on this.
https://oracle-base.com/articles/misc/updates-based-on-queries
From this link - I used a modification of the above query which did not work for me (the answer from mathguy which uses rowid)
MERGE /*+ APPEND PARALLEL(8) */ INTO dest_table tt
USING source_table st
ON (tt.identifier = st.identifier)
WHEN MATCHED THEN
UPDATE SET tt.number = st.number;
Here I have two tables: source and dest. They both have a varchar field in common and I am adding the source identify field (PK) into the dest table.
update table1 a
set a.col1='Y'
where exists(select 1
from table2 b
where a.col1=b.col1
and a.col2=b.col2
)
In Oracle 10g, I want to update the records of the resulting minus query below:
(
SELECT A,B,C FROM Table1
MINUS
SELECT A,B,C FROM Table2
)
The column that is to be updated is not part of the minus query as its not present in both tables so the below code is not an option
UPDATE
(
SELECT A,B,C FROM Table1
MINUS
SELECT A,B,C FROM Table2
)
SET TABLE1.D = 'TEST'
How about:
update table1
set d = 'TEST'
where (a,b,c) not in(select a,b,c from table2);
Edit:
The performance of minus generally suck, due to the sort operation.
If any of {a,b,c} are nullable, try the following instead:
update table1 t1
set t1.d = 'TEST'
where not exists(
select 'x'
from table2 t2
where t2.a = t1.a
and t2.b = t1.b
and t2.c = t1.c
);
In response to your comment about wanting to use the minus clause:
update Table1
set d = 'TEST'
where (a,b,c) in (select a,b,c from Table1 minus select a,b,c from Table2);
I have a table ( table1 ) that represents item grouping and another table ( table2 ) that represents the items themselves.
table1.id is foreign key to table2 and in every record of table1 I also collect information like the total number of records in table2 associated with that particular record and the sum of various fields so that I can show the grouping and a summary of what's in it without having to query table2.
Usually items in table2 are added/removed one at a time, so I update table1 to reflect the changes in table2.
A new requirement arose, choosen items in a group must be moved to a new group. I thought of it as a 3 step operation:
create a new group in table1
update choosen records in table2 to point to the newly created rec in table1
the third step would be to subtract to the group the number of records / the sum of those other fields I need do show and add them to the new group, data that I can find simply querying table2 for items associated with the new group.
I came up with the following statement that works.
update table1 t1 set
countitems = (
case t1.id
when 1 then t1.countitems - ( select count( t2.id ) from table2 t2 where t2.id = 2 )
when 2 then ( select count( t2.id ) from table2 t2 where t2.id = 2 )
end
),
sumitems = (
case t1.id
when 1 then t1.sumitems - ( select sum( t2.num ) from table2 t2 where t2.id = 2 )
when 2 then ( select sum( t2.num ) from table2 t2 where t2.id = 2 )
end
)
where t1.id in( 1, 2 );
is there a way to rewrite the statement without having to repeat the subquery every time?
thanks
Piero
You can use a cursor and a bulk collect update statement on the rowid. That way you can simply write the join query with the desired result and update the table with those values. I always use this function and make slight adjustments each time.
declare
cursor cur_cur
IS
select ti.rowid row_id
, count(t2.id) countitems
, sum(t2.num) numitems
from table t1
join table t2 on t1.id = t2.t1_id
order by row_id
;
type type_rowid_array is table of rowid index by binary_integer;
type type_countitems_array is table of table1.countitems%type;
type type_numitems_array is table of table1.numitems%type;
arr_rowid type_rowid_array;
arr_countitems type_countitems_array;
arr_numitems type_numitems_array;
v_commit_size number := 10000;
begin
open cur_cur;
loop
fetch cur_cur bulk collect into arr_rowid, arr_countitems, arr_numitems limit v_commit_size;
forall i in arr_rowid.first .. arr_rowid.last
update table1 tab
SET tab.countitems = arr_countitems(i)
, tab.numitems = arr_numitems(i)
where tab.rowid = arr_rowid(i)
;
commit;
exit when cur_cur%notfound;
end loop;
close cur_cur;
commit;
exception
when others
then rollback;
raise_application_error(-20000, 'ERROR updating table1(countitems,numitems) - '||sqlerrm);
end;