How to update multiple rows include with-select sentence in Oracle - oracle

I want update table_a 's col1 with a value from another table.
I make a select that is
with tmp as (
blar~
)
select col1 from table_b b, tmp t
where 1=1
and b.col2 = t.col_x
Update join condition
table_a.col3 = table_b.col3

The principle is to create an updateable view like this:
update
( with tmp as ( select col2
from table_c)
select a.col1 as a_col1
, b.col1 as b_col1
, a.id as a_id
from tmp
join table_b b
on b.col2 = tmp.col2
join table_a a
on a.col3 = b.col3
) t
set a_col1 = b_col1
/
The important points are:
we only update one table from the view;
all the other tables in the view have primary or unique keys so they are guaranteed to return only one row.
the unique columns must be referenced in the view
If the update does not fulfil these strictures it will hurl ORA-01779: cannot modify a column which maps to a non key-preserved table.
It's not clear why you want to use a WITH clause but that may make it harder to ensure you're using key-preserved tables. For instance this variant on the above query fails, even though we know DUAL always returns one row.
update
( with tmp as ( select c.col2
from table_c c
join dual d
on d.dummy = c.col2)
select a.col1 as a_col1
, b.col1 as b_col1
, a.id as a_id
from tmp
join table_b b
on b.col2 = tmp.col2
join table_a a
on a.col3 = b.col3
) t
set a_col1 = b_col1
/
If this explanation does not help you arrive at a solution please edit your question to provide more details. Include any error messages you get. "i can't success" is not enough information for us to help you.
"I was use your answer that called /*+ bypass_ujvc */ "
That is an undocumented hint, so it's pretty risky to use in Production. Also, it seems Oracle removed it in 11gR2 and later, so it won't have any effect (which is why using undocumented hints is risky). You should find a solution which works without the hint.

It's hard to help as you didn't provide enough information. However with result can be update in below way:
update (
with temp as (
select col1 from table_a
)
select col1 from temp )
set col1 = 'newValue'

Related

Oracle MINUS operator and delete

You can insert records into table B if they are in table A
insert into B
select * from A
minus
select * from B
How do you delete records that are in B and not in A?
select * from B
minus
select * from A
How to delete records?
The assumption is that we do not have a primary key or a unique one.
You can do it like this:
delete from a2
where (COLUMN1, COLUMN2, COLUMN3, ...) in (select * from a2
minus
select * from a1);
It works, but you have to enter the column names in the where clause. Can not do delete in such a beautiful way as insert into select * from ...?
If you wanted to continue with your current approach, you should not use select * in your minus query. Rather, you should always explicitly list out the columns which you want to use.
But, I would use an EXISTS query here:
DELETE
FROM tableB b
WHERE NOT EXISTS (SELECT 1 FROM tableA a
WHERE a.col1 = b.col1 AND
a.col2 = b.col2 AND
a.col3 = b.col3 AND ...);
Best practice going forward would to have a primary key column in the A table. Then, you would only need to check that column against the B table for uniqueness.

Oracle join clause where varchar2(4 byte) causing issue

Title was tough to choose my wording.
I have 2 tables I want to join together via a lg_code. Both columns are VARCHAR2(4 byte). I am running into an issue where table1 lg_code = 0003 and table2 lg_code = 3. The three 0's are causing an issue with the join and not returning all the data needed. How would I go about writing the join clause to fix this issue?
Code:
select * from table1 t1 JOIN table2 t2 ON t1.LG_CODE = t2.LG_CODE
I would suggest to convert the value of the columnlg_code to number first then make the join:
SELECT * FROM table1 t1
JOIN table2 t2 ON to_number(t1.LG_CODE) = to_number(t2.LG_CODE)
you can also use ltrim() on them:
SELECT * FROM table1 t1
JOIN table2 t2 ON LTRIM(t1.LG_CODE, '0') = LTRIM(t2.LG_CODE, '0');
but in newer versions of oracle SQL*PLUS it trims automatically.

Oracle update statement with analytics is failing

The Table_B contains duplicate records as seen below. What I am trying to do is lookup Table_A using Table_B.SERIAL_NUM and update Table_A .COVERAGE_END coloumn with the most recent Date value in COVERAGE_TO coloumn in Table_B.
Table_B
SERIAL_NUM ,COVERAGE_FROM ,COVERAGE_TO
123456 ,26/12/2014 ,13/12/2015
123456 ,14/12/2015 ,13/12/2016
23456 ,18/12/2014 ,13/12/2015
23456 ,14/12/2015 ,13/12/2016
Following is the update statement I am using.
update Table_A J
set ( J.COVERAGE_END_DATE)
=(select COVERAGE_TO from
(
select SERIAL_NUM, COVERAGE_TO, row_number() over(partition by SERIAL_NUM order by COVERAGE_TO desc) as rn from TABLE_B B
)where rn = 1
)
where exists
(
select * from TABLE_B Q where Q.SERIAL_NUM = J.SERIAL_NUMBER
)
;
However I get the following error
ORA-01427: single-row subquery returns more than one row
Can Some one please help me with this Query?
You have to compare J's SERIAL_NUMBER with B's to get the only proper value.
where rn = 1 and J.SERIAL_NUMBER = SERIAL_NUM
If not, subquery will return max values for every SERIAL_NUM.
I'm not sure why partitioning is needed here.
Would a simple MAX() not produce the needed result?
update table_a
set coverage_end_date = (
select max(coverage_to)
from table_b b inner join table_a a on b.serial_num = a.serial_num
)
;

Oracle - deleting duplicates

I have found the following way for removing duplicates:
DELETE FROM
table_name A
WHERE
a.rowid >
ANY (
SELECT
B.rowid
FROM
table_name B
WHERE
A.col1 = B.col1
AND
A.col2 = B.col2
);
Could someone explain me step by step how does the query works?
TIA!
In Oracle, ROWID is a pseudo column points to the physical location of a row. The query does a self join and fetches those rows which have the same value of column 1 & column 2 - with the assumption that these keys are enough to identify as duplicate row.
Once the rows are fetched, the query then deletes those rowids which are larger than the first row fetched, thereby deleting duplicates
Like this:
DELETE FROM // The command to delete
table_name A //the table in which you want to remove duplicate
WHERE //condition
a.rowid > //checking the rowid which oracle adds to each row. Oracle Database rowid values contain information necessary to locate a row.
ANY ( //any row which has a condition
SELECT //select
B.rowid //rowid
FROM //from
table_name B //table name with alias name as B. Is used for making a self join
WHERE //condition
A.col1 = B.col1 //where the column1 has the same rowid
AND //and
A.col2 = B.col2 //where the column2 has the same rowid
);

Oracle Optimizer Unexpected Results

I have a co worker who wrote the following query. The first one works and the second one does not. Also if you remove the aggregate function from the subquery, it works. The oracle optimizer is doing something weird. Any thoughts? Running in SQL Developer 3.1 against 11.1.0.6.0 64 bit.
This works:
SELECT
a.fd_customer_key
, b.fd_customer_key
, b.counter
FROM FETCH_CUSTOMER a
, (select fd_customer_key, count(*) as counter from fetch_customer_order group by fd_customer_key) b
where a.fd_customer_key = b.fd_customer_key (+)
and b.counter is null
This doesn’t:
SELECT
a.fd_customer_key
, b.fd_customer_key
, b.counter
FROM FETCH_CUSTOMER a
, (select fd_customer_key, count(*) as counter from fetch_customer_order group by fd_customer_key) b
where a.fd_customer_key = b.fd_customer_key (+)
and b.fd_customer_key is null
Actually yes, both of the queries you provided are supposed to wrok the same way, but if i understand your need well, you are trying to select the fd_customer_key which has no Order?
I suggest the following query for your need, its more simple and less consuming :
SELECT a.fd_customer_key
FROM FETCH_CUSTOMER a
WHERE NOT EXISTS (SELECT 1
FROM fetch_customer_order b
WHERE a.fd_customer_key = b.fd_customer_key)
It seems like you are trying to make an anti-join (find the rows from FETCH_CUSTOMER that have no corresponding rows in FETCH_CUSTOMER_ORDER).
With Oracle you do not have to use this clever OUTER JOIN trick to write an anti-join, you could use a NOT IN or NOT EXISTS operator and let the optimizer find the best plan. This will be just as efficient and easier to read.
Anyway, I can't reproduce your findings, here's my setup:
CREATE TABLE a (ID NUMBER PRIMARY KEY);
CREATE TABLE b (a_id NUMBER NOT NULL, DATA VARCHAR2(30));
INSERT INTO a (SELECT object_id FROM all_objects);
INSERT INTO b (SELECT object_id, object_name
FROM all_objects WHERE object_type = 'VIEW');
SELECT a.id, b.a_id, b.cnt
FROM a, (SELECT a_id, COUNT(*) cnt FROM b GROUP BY a_id) b
WHERE a.id = b.a_id (+)
AND b.cnt IS NULL;
SELECT a.id, b.a_id, b.cnt
FROM a, (SELECT a_id, COUNT(*) cnt FROM b GROUP BY a_id) b
WHERE a.id = b.a_id (+)
AND b.a_id IS NULL;
You will find that both queries return rows. What is your DB version?

Resources