How to update and set values based on multiple joins in select statment? - oracle

I want to update a column prtnum and revlvl in table invdtl based on value from select statment, here is the code
update invdtl set invdtl.prtnum = usr_prtmst_xref.prtnum,invdtl.revlvl =
usr_prtmst_xref.colnam ([select
invdtl.prtnum,usr_prtmst_xref.prtnum AS
crossref,invdtl.revlvl,aremst.arecod,aremst.fwiflg from invdtl
join usr_prtmst_xref
on usr_prtmst_xref.prtnum = usr_prtmst_xref.prtnum
join invsub
join invlod
join locmst
join aremst
on aremst.arecod = locmst.arecod
and aremst.wh_id = locmst.wh_id
on locmst.stoloc = invlod.stoloc
and locmst.wh_id = invlod.wh_id
on invlod.lodnum = invsub.lodnum
on invsub.subnum = invdtl.subnum where aremst.arecod = 'EXPR' or
aremst.fwiflg = '1' and rownum <2])
I want to copy two values prtnum and revlvl that are returned by select statement but there is some syntax issue.

There are a bunch of errors here:
The syntax for a multi-column update is basically
update blah
set ( col1, col2 ) = ( select x, y
from
...
)
The syntax for multiple joins is basically
from table1 t1
join table2 t2
on t1.col = t2.col
join table3 t2 on
t2.col = ...
Get ride of "[" and "]"
The predicate rownum<2 is probably to get around the message you received, something like "single row sub-query returns more than 1
row" Which this predicate "fixes" that problem, you are just getting
the first random row; probably not what you want. You probably need to
correlate the sub-query with the update
I would fix these basic syntax errors and try again.

Related

Oracle Merge Into (Multiple Joined Tables) Update Set (Multiple Where Statements) Returns Invalid Column Specification

I am new to Oracle. I am trying to update the values of a table with the values from a SELECT DISTINCT statement using the MERGE INTO method. I want to update the values for a table based on what is in the USING table conditionally.
A quick diagram of what I am essentially going for is
MERGE
INTO update_table ut
USING
(SELECT DISTINCT
t1.column_1
,t2.column_2
FROM table_1 t1
INNER JOIN table_2 t2
ON t1.foreign_key = t2.primary_key) st
ON (ut.pk = st.column_1)
WHEN MATCH UPATE
SET(ut.update_column = st.column_2
WHERE st.column_1 = 1
AND st.column_2 = 1
,ut.update_column = st.column_2
WHERE st.column_1 = 2
AND st.column_2 = 2);
However, when I do so I get the INVALID COLUMN SPECIFICATION error on the line where I use SET. How can I work around this to successfully update the table, preferably in ANSI standard?
You can include the conditions that you have added in where clause in the selected column list in using clause itself. Like This. (Not tested. Your conditions in where clause were not appropriate)
MERGE
INTO update_table ut
USING (SELECT DISTINCT
t1.column_1 ,
CASE
WHEN t1.column_1 = 1
AND t2.column_2 = 1
THEN t2.column_1
WHEN t1.column_1 = 2
AND t2.column_2 = 2
THEN t2.column_2
END column_2
FROM
table_1 t1
INNER JOIN table_2 t2 ON t1.foreign_key = t2.primary_key
) st
ON (ut.pk = st.column_1)
WHEN MATCHED THEN
UPDATE SET ut.update_column = st.column_2 ;

cant update a column from table it returns single-row subquery returns more than one

When i execute the following query, i get the message like
Ora-01427 single-row subquery returns more than one row
I am trying to update "City" column in Table A From another table.
How would I do this?
table A: Name, PER_code(it also has duplicated value or null), city, PD_code
table B: Name, PER_code(No duplicated value,Maybe null), city, Postal_code
The update statement:
UPDATE A
SET (A.city) =
(SELECT B.city
FROM B
INNER JOIN A
ON A.per_code=B.per_code
WHERE A.per_code is not null)
Since there are duplicate values but you select only one field, you modify your query from
UPDATE A SET (A.city) = (SELECT B.city FROM B INNER JOIN A ON
A.per_code=B.per_code WHERE A.per_code is not null)
to
UPDATE A SET (A.city) = (SELECT DISTINCT B.city FROM B INNER JOIN A ON
A.per_code=B.per_code WHERE A.per_code is not null)
The distinct operator will allow you to keep a single value if it's duplicated in the table B. If there are multiple distinct values, you will have to look at your data and make a decision about which value should be used in the other table.
You can also try MERGE INTO selecting DISTINCT records.
MERGE INTO A d
USING
( SELECT DISTINCT per_code, city FROM B ) s
ON ( s.per_code = d.per_code )
WHEN MATCHED THEN UPDATE SET d.City = s.City
WHERE d.per_code IS NOT NULL;
I think you intend a correlated subquery:
UPDATE A
SET city = (SELECT B.city
FROM B
WHERE A.per_code = B.per_code
)
WHERE A.per_code is not null;
EDIT:
The above should work given the constraints in the original question. If it does not, it is easily adaptable:
UPDATE A
SET city = (SELECT B.city
FROM B
WHERE A.per_code = B.per_code AND rownum = 1
)
WHERE A.per_code is not null;

INSERT ALL statement incredibly slow, even when no records to insert

This is on 11g. I have an INSERT ALL statement which uses a SELECT to build up the values to insert. The select has some subqueries that check that the record doesn't already exist. The problem is that the insert is taking over 30 minutes, even when there are zero rows to insert. The select statement on its own runs instantly, so the problem seems to be when it is used in conjunction with the INSERT ALL. I rewrote the statement to use MERGE but it was just as bad.
The table has no triggers. There is a primary key index, and a unique constraint on two of the columns, but nothing else that looks like it might be causing an issue. It currently has about 15000 rows, so definitely not big.
Has anyone a suggestion for what might be causing this, or how to go about debugging it?
Here's the INSERT ALL statement.
insert all
into template_letter_merge_fields (merge_field_id, letter_type_id,table_name,field_name,pretty_name, tcl_proc)
values (template_let_mrg_fld_sequence.nextval,letter_type_id,table_name,field_name, pretty_name, tcl_proc)
select lt.letter_type_id,
i.object_type as table_name,
i.interface_key as field_name,
i.pretty_name as pretty_name,
case
when w.widget = 'dynamic_select' then
'dbi::'||i.interface_key||'::get_name'
when w.widget = 'category_tree' and
i.interface_key not like '%_name' and
i.interface_key not like '%_desc' then
'dbi::'||i.interface_key||'::get_name'
else
'dbi::'||i.interface_key||'::get_value'
end as tcl_proc
from template_letter_types lt,
dbi_interfaces i
left outer join acs_attributes aa on (aa.object_type||'_'||aa.attribute_name = i.interface_key
and decode(aa.object_type,'person','party','aims_organisation','party',aa.object_type) = i.object_type)
left outer join flexbase_attributes fa on fa.acs_attribute_id = aa.attribute_id
left outer join flexbase_widgets w on w.widget_name = fa.widget_name
where i.object_type IN (select linked_object_type
from template_letter_object_map lom
where lom.interface_object_type = lt.interface_object_type
union select lt.interface_object_type from dual
union select 'template_letter' from dual)
and lt.interface_object_type = lt.interface_object_type
and not exists (select 1
from template_letter_merge_fields m
where m.sql_code is null
and m.field_name = i.interface_key
and m.letter_type_id = lt.letter_type_id)
and not exists (select 1
from template_letter_merge_fields m2
where m2.pretty_name = i.pretty_name
and m2.letter_type_id = lt.letter_type_id)

ORACLE - Update Multiple Columns with Values from Nested Join

I'm practically new in using oracle and I bumped into a blocker. Below is the query that I created based on what I have researched online to update multiple columns of a table with values from a nested join statement.
UPDATE
(
SELECT
A.COLUMN1 OLD_COLUMN1,
BC.COLUMN1 NEW_COLUMN1,
A.BALANCE OLD_COLUMN2,
BC.COLUMN2_MIN NEW_COLUMN2,
A.COLUMN3 OLD_COLUMN3,
BC.COLUMN3 NEW_COLUMN3
FROM TABLE_A A
INNER JOIN
(
SELECT B.TWWID,
B.ITEMDATE,
B.COLUMN2_MIN,
C.COLUMN3,
C.COUNTRYID,
C.COLUMN1
FROM TABLE_B B
LEFT OUTER JOIN TABLE_C C
ON TO_CHAR(B.ID) = TO_CHAR(C.ID)
) BC
ON A.ID = BC.ID
AND A.DATE = BC.DATE
)ABCUPDATE
SET ABCUPDATE.OLD_COLUMN1 = ABCUPDATE.NEW_COLUMN1,
ABCUPDATE.OLD_COLUMN2 = ABCUPDATE.NEW_COLUMN2,
ABCUPDATE.OLD_COLUMN3 = ABCUPDATE.NEW_COLUMN3;
Selecting the sub-query returns the expected results but when I run the update script as a whole an error is returned.
ORA-01779: cannot modify a column which maps to a non key-preserved
table
Can anyone please explain why I encounter this error and what adjustments can I do to the script to make it work?
Thanks in advance!

Why sub SQL in FROM area can't be null?

select col_1,
col_2
from tbl_a A,
tbl_b B,
( select col_1,col_2 from tbl_c where clo_c_1 <> '1' ) C
where A.col_1 = B.col_1
and A.col_2 = B.col_2
and (A.col_2 = B.col_2
or C.col_2 = A.col_2);
My environment is Oracle,when I run this SQL,if the sub SQL C hasn't got a result,then the entire SQL returns NULL.Whereas if C has a result(not null) which fits other condions,there could be a result.Would somebody explain why sub SQL at the from area need to be not NULL?Thanks very much.
You need to bring yourself into the 90s and start using standard joins:
select col_1,
col_2
from tbl_a A
inner join
tbl_b B
on A.col_1 = B.col_1
and A.col_2 = B.col_2
left join
( select col_1,col_2 from tbl_c where clo_c_1 <> '1' ) C
on
C.col_2 = A.col_2
As a guess. I'm not entirely sure what your join conditions should be but that's my first attempt.
This is expected behaviour. When you join two result sets, you only want to get results where the join criteria is satisfied. If the criteria are not satisfied, you should get no results.
If I run the query "get me all the employees older than 65, and get their departments", if there are no employees older than 65, you would not expect to get any results, even if there are some departments in the database.
SELECT emp.name, dept.dept_name
FROM emp
JOIN dept
ON (emp.dept_no = dept.dept_no)
WHERE emp.age > 65;
As the others said, if you actually want to get rows regardless of whether the subquery has any results, you need to use an outer join.

Resources