performing an update query with a select subquery returning ora-01427 error - oracle

I need to update a column in one table with the results from a select sub-query (and they should ultimately be different). But When I do this, I get the 'ORA-01427: single row sub-query returns more than one row query' error.
Can you please take a look and see what it is that I am overlooking? (I could just be overlooking something simple for all I know)
UPDATE AIRMODEL_NETWORK_SUMMARY ans
SET ANS.NBR_RETURNS = (
SELECT SUM(RQ.RETURN_QTY)
FROM RETURN_QTY RQ JOIN AIRMODEL_NETWORK_SUMMARY ANS ON RQ.LOC_ID = ANS.LOC_ID
WHERE RQ.FSCL_YR_NUM = ans.FSCL_YR_NUM
AND RQ.FSCL_WK_IN_YR_NUM =
ans.FSCL_WK_IN_YR_NUM
GROUP BY ANS.LOC_ID,
ans.FSCL_WK_IN_YR_NUM,
ANS.FSCL_YR_NUM
);

I think that your inner query is not well correlated to the table that you're trying to update. Please look here Oracle SQL: Update a table with data from another table. You should add some kind of a where condition that ties the rows you're trying to update with the values calculated by the inner statement.

Related

Oracle trying to update a table by joining a non indexed table

I tried looking for a similar example to my problem but could not reproduce the solution to my success.
I have 2 tables, Controller and Actions.
The Actions table has the columns Step, Script, Description, Wait_Until and Ref_Code.
The Controller table can only be joined on the Action table by the Ref_Code.
The Action table cannot have a PK because for each Ref_Code there is a Step to be taken.
Im getting an error when trying to update the Controller table using a merge statement:
ORA-30926: unable to get a stable set of rows in the source tables
My merge statement is as follows:
MERGE INTO DSTETL.SHB_FTPS_CONTROLLER ftpsc
USING (SELECT DISTINCT FTPSC.SESSION_ID,
FTPSC.ORDER_DATE,
sa.step,
sa.next_step,
LAST_ACTION_TMSTMP,
SA.ACTION_SCRIPT,
sa.ref_code,
SA.WAIT_UNTIL
FROM DSTETL.SHB_FTPS_CONTROLLER ftpsc, DSTETL.SHB_ACTIONS sa
WHERE SA.REF_CODE = FTPSC.REF_CODE
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step) v1
ON (v1.REF_CODE = FTPSC.REF_CODE)
WHEN MATCHED
THEN
UPDATE SET FTPSC.LAST_ACTION_TMSTMP = CURRENT_TIMESTAMP,
ftpsc.next_step = v1.next_step,
ftpsc.curr_step = v1.STEP,
ftpsc.action_script = v1.action_script
WHERE CURRENT_TIMESTAMP >= v1.LAST_ACTION_TMSTMP + v1.WAIT_UNTIL;
COMMIT;
I tried doing this using a normal update as well but Im getting ORA-01732: data manipulation operation not legal on this view.
UPDATE (SELECT FTPSC.SESSION_ID,
FTPSC.ORDER_DATE,
FTPSC.CURR_STEP,
FTPSC.NEXT_STEP,
FTPSC.ACTION_SCRIPT,
sa.step, --New Step
sa.next_step AS "NNS", --New Next Step
FTPSC.LAST_ACTION_TMSTMP,
SA.ACTION_SCRIPT AS "NAS", --New action script
sa.ref_code,
SA.WAIT_UNTIL
FROM DSTETL.SHB_FTPS_CONTROLLER ftpsc
LEFT JOIN
DSTETL.SHB_ACTIONS sa
ON SA.REF_CODE = FTPSC.REF_CODE
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step) t
SET t.curr_step = t.step,
t.LAST_ACTION_TMSTMP = CURRENT_TIMESTAMP,
t.next_step = t."NNS",
t.action_script = t."NAS";
COMMIT;
Any advice would be appreciated, I already understand this is because the Action table has multiple Ref_Codes but REF_CODE||STEP is unique. And the output of:
SELECT DISTINCT FTPSC.SESSION_ID,
FTPSC.ORDER_DATE,
sa.step,
sa.next_step,
LAST_ACTION_TMSTMP,
SA.ACTION_SCRIPT,
sa.ref_code,
SA.WAIT_UNTIL
FROM DSTETL.SHB_FTPS_CONTROLLER ftpsc, DSTETL.SHB_ACTIONS sa
WHERE SA.REF_CODE = FTPSC.REF_CODE
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step;
Is how I want the Controller table to be updated like.
Thanks in advance.
It sounds like what you want to do is: update each row in the Controller table with the matching "next step" details from the Actions table. But your Merge statement is querying the Controller table twice, which confuses things.
Is this what you're trying to do?
MERGE INTO DSTETL.SHB_FTPS_CONTROLLER ftpsc
USING (SELECT
step,
next_step,
ACTION_SCRIPT,
ref_code,
WAIT_UNTIL
FROM DSTETL.SHB_ACTIONS
) sa
ON (sa.REF_CODE = FTPSC.REF_CODE)
WHEN MATCHED
THEN
UPDATE SET FTPSC.LAST_ACTION_TMSTMP = CURRENT_TIMESTAMP,
ftpsc.next_step = sa.next_step,
ftpsc.curr_step = sa.STEP,
ftpsc.action_script = sa.action_script
WHERE CURRENT_TIMESTAMP >= ftpsc.LAST_ACTION_TMSTMP + sa.WAIT_UNTIL
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step;
EDIT: updated query
EDIT2: So, in your original query, in the USING section you were selecting the rows in the Controller table that you wanted to update... but you never joined those rows to the Controller table from the MERGE INTO section to match them up. Having the same alias "ftpsc" just made it less clear that they're two separate objects in the query, and which one you wanted to update.
Honestly I don't really understand why Oracle won't let you update columns that appear in the USING..ON clause. It apparently works fine in SQL Server.

Oracle - Update COUNT of rows with specific value

This question has been posted several times but I am not able to get it work. I tried the approach mentioned in Update column to the COUNT of rows for specific values in another column. SQL Server. It gives me SQLException: java.sql.SQLException: ORA-01427: single-row subquery returns more than one row error not sure what I can do.
Below is my problem
UPDATE dataTable
SET ACCX = (select b.cnt
from dataTable a
join
(SELECT Account,
COUNT(1) cnt
FROM dataTable
GROUP BY Account) b
on a.Account=b.Account)
,ACCR = 15481
,ACCF = 3
WHERE ID = 1625
I only have the access & can change to the bold part since rest of the query is generated by the tool I cannot change it & I have to update ACCX column with the count of the value in column Account. Is it possible to do?
Note: - Account column is already populated with values.
You cannot follow that query because it is for sqlserver and NOT oracle. It is simpler in oracle and does not need a join to itself.
This update will set the count for id 1625 only based on number of account numbers in datatable. See demo here;
http://sqlfiddle.com/#!4/d154c/1
update dataTable a
set ACCR = 15481,
ACCF = 3,
a.ACCX = (
select COUNT(*)
from dataTable b
where b.Account=a.Account)
WHERE a.ID = 1625;

ORA-017779 : cannot modify a column which maps to non key-preserved table

How can I solve this error:
ORA-017779 : cannot modify a column which maps to non key-preserved table.
My Code:
UPDATE (SELECT SOBS034.T1 as OLD, SOBS063.T1 as NEW
FROM SOBS034
INNER JOIN SOBS063 ON SOBS034.ID = SOBS063.ID
where SOBS034.ID='111000' AND SOBS063.T2='' ) t
SET t.OLD =t.NEW
To update a JOIN, Oracle needs to be absolutely sure that for each row of the table you are trying to update, there will be at most one row of the joined table.
Here you'll be able to update the join if and only if SOBS063.ID is unique (explicitely declared by a unique constraint/pk).
If somehow SOBS063.ID is unique for this record with your join condition but is not declared as such, you won't be able to use this method. You could however transform this DML into an equivalent MERGE, something like this:
MERGE INTO SOBS034 a
USING SOBS063 b
ON (a.id = b.id AND a.ID='111000' AND b.T2 IS NULL)
WHEN MATCHED THEN UPDATE SET a.t1 = b.t1;
By the way SOBS063.T2='' is never true in Oracle right now.
Try to create a unique index on SOBS034 (ID) and SOBS063 (ID).

Compare first row to other rows

The issue I face that I need after selecting multiple rows,to loop over each row and fetch those who have some related information to the first row.
Example:
select NAME,ENGLISH_GRADE,FRANCE_GRAE
from (some complex query that have order by and returns 100 rows) WHOLE_ROWS
where
//Here I need to loop over WHOLE_ROWS and make something like that:
//if(currentRow.ENGLISH_GRADE==WHOLE_ROWS(0).ENGLISH_GRADE)
//fetch this row
Basically, you need to join your query to itself. You can do with with a subquery factoring clause:
WITH complex_query AS
( ... complex query here ... )
SELECT
FROM complex_query cq1
WHERE cq1.english_grade = ( SELECT english_grade FROM cq1
WHERE rownum = 1 )
Here is a SQL Fiddle. You could also do this with analytics, but those seem to me more difficult to understand.

Hint oracle to use indexes on the subquery -- Oracle SQl

I have a query as follows
select *
from
( select id,sum(amt) amt from table_t group by id
) t inner join table_v v on (v.id = t.id)
order by t.amt desc;
table_t has no index and has 738,000 rows and table_v has an index on id and has 158,000 rows.
The query currently fetches the results in 10 seconds.
The explain query plan shows a full table scan.. How can I improve the performance here ?
If I add an index on id for table_t will it help. Because I am using it in a subquery ?
If you have an index on (id,amt) you would minimise the work in the group by/summation process (as it could read the index). If both columns are nullable then you may need to add a "where id is not null" so it will use the index. [That's implied by the later join on id, but may not get inferred by the optimizer.]
Next step would be to use a materialized view for the summation, maybe with an index on (amt,id) (which it could use to avoid the sort). But that is refreshed either at a commit or on request or at scheduled intervals. It doesn't help if you need to do this query as part of a transaction.
Both the index and the materialized view would add work to inserts/updates/deletes on the table but save work in this query.

Resources