Requirement in Oracle PL/SQL to update labels - oracle

I have 2 tables - tab1 , tab2 with following data
tab1 data:
OID Label
1 MX1
1 MX2
1 MX3
2 MX4
2 MX5
tab2 data:
OID ID Label
1 5678
1 2347
1 9687
2 4567
2 3455
The join condition between these two tables is oid column.I need to create a process which will update Label column from tab1 to Label column of tab2.It doesn't matter which label gets assigned to which record of tab2 for a particular oid. The only check that needs to happen is that both the tables should have same number of records for an oid.The final outcome should be the following
tab2 data:
OID ID Label
1 5678 MX1
1 2347 MX2
1 9687 MX3
2 4567 MX4
2 3455 MX5
Again, it doesn't matter which label gets assigned to tab2 for a particular oid,but the same label cannot be repeated for a particular oid.What would be the best way to write a code for this requirement?

Here is a sql solution:
merge into tab2
using
(
select t2."id" as ide,t1."label" labela from
(select rownum n,"label","oid" from tab1 order by "oid")t1,
(select rownum n, a2.* from tab2 a2 order by "oid")t2
where t1.n=t2.n and
t1."oid"=t2."oid"
) tb4
on (tab2."id" = tb4.ide)
when matched then
update set tab2."label" = tb4.labela;
Result:
oid| id | label
-----------------
1 5678 mx1
1 2347 mx2
1 9687 mx3
2 4567 mx4
2 3455 mx5

Sample tables:
SQL> select * from tab1 order by oid, label;
OID LAB
---------- ---
1 mx1
1 mx2
1 mx3
2 mx4
2 mx5
SQL> select * from tab2 order by oid, id;
OID ID LAB
---------- ---------- ---
1 2347
1 5678
1 9687
2 3455
2 4567
SQL>
This is query that returns desired result:
SQL> with
2 t1 as (select oid, label, rowid rwid,
3 row_number() over (partition by oid order by label) rn
4 from tab1
5 ),
6 t2 as (select oid, id, rowid rwid,
7 row_number() over (partition by oid order by id) rn
8 from tab2
9 )
10 select b.oid, b.id, a.label
11 from t1 a join t2 b on a.oid = b.oid and a.rn = b.rn;
OID ID LAB
---------- ---------- ---
1 2347 mx1
1 5678 mx2
1 9687 mx3
2 3455 mx4
2 4567 mx5
SQL>
A few options I tried: correlated update won't work because of
ORA-01779: cannot modify a column which maps to a non key-preserved table
SQL> update (
2 with
3 t1 as (select oid, label, rowid rwid,
4 row_number() over (partition by oid order by label) rn
5 from tab1
6 ),
7 t2 as (select oid, id, rowid rwid, label,
8 row_number() over (partition by oid order by id) rn
9 from tab2
10 )
11 select b.oid, b.id, b.label b_label, a.label a_label
12 from t1 a join t2 b on a.oid = b.oid and a.rn = b.rn
13 )
14 set b_label = a_label;
set b_label = a_label
*
ERROR at line 14:
ORA-01779: cannot modify a column which maps to a non key-preserved table
SQL>
MERGE won't work because of
ORA-01732: data manipulation operation not legal on this view
SQL> merge into
2 (select oid, id, label, row_Number() over (partition by oid order by id ) rn from tab2) b
3 using (select oid, label, row_number() over (partition by oid order by label) rn from tab1) a
4 on (a.oid = b.oid and
5 a.rn = b.rn)
6 when matched then update set
7 b.label = a.label;
(select oid, id, label, row_Number() over (partition by oid order by id ) rn from tab2) b
*
ERROR at line 2:
ORA-01732: data manipulation operation not legal on this view
SQL>
Merge would accept a view (created with create view ...), but a view has to be updateable; this one can't be because it contains analytic function.
What's left is a PL/SQL procedure:
SQL> begin
2 for cur_r in (with
3 t1 as (select oid, label, rowid rwid,
4 row_number() over (partition by oid order by label) rn
5 from tab1
6 ),
7 t2 as (select oid, id, rowid rwid,
8 row_number() over (partition by oid order by id) rn
9 from tab2
10 )
11 select b.rwid, a.label
12 from t1 a join t2 b on a.oid = b.oid and a.rn = b.rn
13 )
14 loop
15 update tab2 b set
16 b.label = cur_r.label
17 where b.rowid = cur_r.rwid;
18 end loop;
19 end;
20 /
PL/SQL procedure successfully completed.
SQL> select * from tab2 order by oid, id;
OID ID LAB
---------- ---------- ---
1 2347 mx1
1 5678 mx2
1 9687 mx3
2 3455 mx4
2 4567 mx5
SQL>
Maybe someone has another idea; I'd like to see it & learn something new.

Related

Converting rows into Column in Oracle without any relation

I have a query which will fetch two rows only and I want to bring second row data into columns with different column name.
Below is the original query result.
The expected result is like
Expected result.
Please help how shd I proceed, not able to figure out with PIVOT.
Here's one option; see comments within code.
SQL> with
2 your_query (column1, column2, column3) as
3 -- this is what your current query returns
4 (select 1, 'ABC', 123 from dual union all
5 select 2, 'XYZ', 456 from dual
6 ),
7 temp as
8 -- distinguish 1st from 2nd row
9 (select y.*,
10 row_number() over (order by column1) rn
11 from your_query y
12 )
13 -- finally, cross join two rows and conditionally display columns.
14 -- MAX is here to avoid empty "cells"
15 select max(case when a.rn = 1 then a.column1 end) as col1,
16 max(case when a.rn = 1 then a.column2 end) as col2,
17 max(case when a.rn = 1 then a.column3 end) as col3,
18 --
19 max(case when b.rn = 2 then b.column1 end) as col4,
20 max(case when b.rn = 2 then b.column2 end) as col5,
21 max(case when b.rn = 2 then b.column3 end) as col6
22 from temp a cross join temp b;
COL1 COL COL3 COL4 COL COL6
---------- --- ---------- ---------- --- ----------
1 ABC 123 2 XYZ 456
SQL>

Sum 2 columns from multiple rows with same ID

Currently, I have a table MY_TABLE like below:
ID ACCT_TYPE CREDIT_AMT DEBIT_AMT
-- --------- ---------- ---------
1 CDT_01 4 (null)
1 DBT_01 (null) 6
One ID can have multiple ACCT_TYPE like above, and each type has its own amount.
I want to just select the row which has ACCT_TYPE like 'CDT_%' but also the total_amount column which is the total of credit_amt and debit_amt column for the same ID.
My expected output like below:
ID ACCT_TYPE TOTAL_AMT
-- --------- ---------
1 CDT_01 10
I tried with this select statement below but it's no use, I think it's because of different ACCT_TYPE:
Select ID, ACCT_TYPE, SUM(NVL(CREDIT_AMT, 0) + NVL(DEBIT_AMT, 0)) TOTAL_AMT
FROM MY_TABLE WHERE ACCT_TYPE LIKE 'CDT_%' GROUP BY ID, ACCT_TYPE;
Here is the output of the select statement above:
ID ACCT_TYPE TOTAL_AMT
-- --------- ---------
1 CDT_01 4
I just begin to learn some query so I don't know is it really possible to get my expected output.
One way to do it is like below:
with inputs (ID, ACCT_TYPE, CREDIT_AMT, DEBIT_AMT) as
(
select 1, 'CDT_01', 4, null from dual union all
select 1, 'DBT_01', null, 6 from dual
),
prep as
(
select t.*, sum(nvl(credit_amt,0)) over (partition by id) + sum(nvl(debit_amt,0)) over (partition by id) as sum_per_id
from inputs t
)
select id, acct_type, sum_per_id
from prep
where acct_type like 'CDT_%';
Output:
A correlated subquery might be one option; sample data (thank you, #Ranagal) in lines #1 - 5; query that does the job begins at line #6.
SQL> with inputs (ID, ACCT_TYPE, CREDIT_AMT, DEBIT_AMT) as
2 (
3 select 1, 'CDT_01', 4, null from dual union all
4 select 1, 'DBT_01', null, 6 from dual
5 )
6 select a.id,
7 a.acct_type,
8 (select sum(nvl(b.credit_amt, 0)) +
9 sum(nvl(b.debit_amt , 0))
10 from inputs b
11 where b.id = a.id
12 ) total_amt
13 from inputs a
14 where acct_type like 'CDT%';
ID ACCT_T TOTAL_AMT
---------- ------ ----------
1 CDT_01 10
SQL>

Oracle update from random on another table

I have some fields in table1 to update with random values from some fields in table2.
I have to random into rows of table2 and update each rows of table1 with the same rows values of table2.
Here is my SQL code, but it doesn't work.
update owner.table1 t1
set (t1.adress1, t1.zip_code, t1.town) = (select t2.adress, t2.zip_code, t2.town
from table1 t2
where id = trunc(dbms_random.value(1,20000)))
Result: all rows are updated with the same values, like no random on table 2 rows
How about switching to analytic ROW_NUMBER function? It doesn't really create a random value, but might be good enough.
Here's an example: first, create test tables and insert some data:
SQL> create table t1 (id number,address varchar2(20), town varchar2(10));
Table created.
SQL> create table t2 (id number, address varchar2(20), town varchar2(10));
Table created.
SQL> insert into t1
2 select 1, 'Ilica 20', 'Zagreb' from dual union all
3 select 2, 'Petrinjska 30', 'Sisak' from dual union all
4 select 3, 'Stradun 12', 'Dubrovnik' from dual;
3 rows created.
SQL> insert into t2
2 select 1, 'Pavelinska 15', 'Koprivnica' from dual union all
3 select 2, 'Baščaršija 11', 'Sarajevo' from dual union all
4 select 3, 'Riva 22', 'Split' from dual;
3 rows created.
SQL> select * From t1 order by id;
ID ADDRESS TOWN
---------- -------------------- ----------
1 Ilica 20 Zagreb
2 Petrinjska 30 Sisak
3 Stradun 12 Dubrovnik
SQL> select * From t2 order by id;
ID ADDRESS TOWN
---------- -------------------- ----------
1 Pavelinska 15 Koprivnica
2 Baščaršija 11 Sarajevo
3 Riva 22 Split
Update t1 with rows from t2:
SQL> update t1 set
2 (t1.address, t1.town) =
3 (select x.address, x.town
4 from (select row_number() over (order by address) id, t2.address, t2.town
5 from t2
6 ) x
7 where x.id = t1.id);
3 rows updated.
SQL> select * From t1 order by id;
ID ADDRESS TOWN
---------- -------------------- ----------
1 Baščaršija 11 Sarajevo
2 Pavelinska 15 Koprivnica
3 Riva 22 Split
SQL>

How to combine 2 select statements in oracle

i have table test2.it contains
ID
1
4
5
10
now i found missing numbers in this sequence.with this query
SELECT min_ID - 1 + level mn FROM
( SELECT MIN(ID) min_ID , MAX(ID) max_ID FROM test2 )
CONNECT BY level <= max_ID - min_ID + 1 minus SELECT ID FROM test2
output is:
MN
---
2
3
6
7
8
9
now i want to combine these 2 columns.I am unable to do this please help me.
i want output like
1 2
4 3
7 5
10 6
8
9
Oracle Setup:
CREATE TABLE test2 (id) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 4 FROM DUAL UNION ALL
SELECT 5 FROM DUAL UNION ALL
SELECT 10 FROM DUAL;
Query:
WITH bounds ( mn, mx ) AS (
SELECT MIN( id ), MAX( id ) FROM test2
),
missing (id, rn) AS (
SELECT id, ROWNUM
FROM (
SELECT mn + LEVEL AS id
FROM bounds
CONNECT BY LEVEL < MX - MN
MINUS
SELECT id
FROM test2
)
),
existing ( id, rn ) AS (
SELECT id, ROWNUM
FROM test2
)
SELECT e.id, m.id
FROM existing e
FULL OUTER JOIN
missing m
ON ( e.rn = m.rn );
Output
ID ID
---------- ----------
1 2
4 3
5 6
10 7
9
8

scalar subquery has an aggregate operation

My oracle version is 10.2.
It's very strange when a scalar subquery has an aggregate operation.
my table named t_test looked like this;
t_id t_name
1 1
2 1
3 2
4 2
5 3
6 3
query string looked like this;
select t1.t_id,
(select count(t_name)
from (select t2.t_name
from t_test t2
where t2.t_id=t1.t_id
group by t2.t_name)) a
from t_test t1
this query's result is,
t_id a
1 3
2 3
3 3
4 3
5 3
6 3
which is very weird,
take t1.t_id=1 for example,
select count(t_name)
from (select t2.t_name
from t_test t2
where t2.t_id=1
group by t2.t_name)
the result is 1,
somehow,the 'where' operator doesn't work,the result is exactly the same as I put my query like this:
select t1.t_id,
(select count(t_name)
from (select t2.t_name
from t_test t2
group by t2.t_name)) a
from t_test t1
why?
Can you post a cut-and-paste from SQL*Plus showing exactly what query you're running? The query you posted does not appear to be valid-- the alias t1 is not going to be valid in the subquery where you're referencing it. That makes me suspect that you're simplifying the problem to post here but you've accidentally left something important out.
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 1 id, 1 name from dual union all
3 select 2,1 from dual union all
4 select 3,2 from dual union all
5 select 4,2 from dual union all
6 select 5,3 from dual union all
7 select 6,3 from dual
8 )
9 select t1.id
10 ,(select count(b.name)
11 from (select t2.name
12 from x t2
13 where t2.id = t1.id
14 group by t2.name) b) a
15* from x t1
SQL> /
where t2.id = t1.id
*
ERROR at line 13:
ORA-00904: "T1"."ID": invalid identifier
Presumably, it would be much more natural to write the query like this (assuming you really want to use a scalar subquery) where t1 is going to be a valid alias in the scalar subquery.
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 1 id, 1 name from dual union all
3 select 2,1 from dual union all
4 select 3,2 from dual union all
5 select 4,2 from dual union all
6 select 5,3 from dual union all
7 select 6,3 from dual
8 )
9 select t1.id
10 ,(select count(t2.name)
11 from x t2
12 where t2.id = t1.id) cnt
13* from x t1
SQL> /
ID CNT
---------- ----------
1 1
2 1
3 1
4 1
5 1
6 1
6 rows selected.

Resources