Insert record from one table to another table - Oracle - oracle

I have a table TABLE1 which has 5 columns (ROLL_NO, NAME, UNITS, CODE, AMOUNT);
CREATE TABLE TABLE1 (ROLL_NO VARCHAR2(3), NAME VARCHAR2(4), UNITS NUMBER, AMOUNT NUMBER, CODE VARCHAR2(3));
------------------------------------------------------------------------------------------
INSERT INTO TABLE1 VALUES ('101', 'JOHN', 1, 6, 'ABC');
INSERT INTO TABLE1 VALUES ('101', 'JOHN', 2, 6, 'ABC');
INSERT INTO TABLE1 VALUES ('102', 'TOMS', 1, 7, 'ABC');
INSERT INTO TABLE1 VALUES ('102', 'TOMS', 6, 7, 'ABC');
INSERT INTO TABLE1 VALUES ('103', 'FINN', 1, 1, 'BCD');
ROLL_NO NAME UNITS AMOUNT CODE
-------------------------------------------------------
101 JOHN 1 6 ABC
101 JOHN 2 6 ABC
-------------------------------------------
102 TOMS 1 7 ABC
102 TOMS 6 7 ABC
103 FINN 1 1 BCD
There is second table TABLE2 where we need to insert data from TABLE1
CREATE TABLE TABLE2 (ROLL_NO VARCHAR2(3), NAME VARCHAR2(4), RESULT VARCHAR2(3));
There are three conditions to insert data into TABLE2
1st case : If CODE is 'ABC' and SUM(UNITS) of particular ROLL_NO is equal to AMOUNT then don't insert data into TABLE2
2nd case : If CODE is 'ABC' and SUM(UNITS) of particular ROLL_NO is not equal to AMOUNT then insert data with RESULT column value as 'YES'
3rd case : If CODE is not 'ABC' then RESULT column will be 'YES'.
Note: NAME, CODE and AMOUNT will be same for particular ROLL_NO though ROLL_NO has multiple UNITS.
Example :
ROLL_NO 102 CODE 'ABC' and two lines with SUM(UNITS) as 7 and its equal to AMOUNT i.e. 7 and (1st case)
ROLL_NO 101 has CODE 'ABC' and two lines with SUM(UNITS) as 3 and its not equal to AMOUNT i.e. 6 (2nd case)
ROLL_NO 103 has CODE 'BCD' which is not equal to 'ABC'(3rd case)
At the end TABLE2 should have
ROLL_NO NAME RESULT
-----------------------------
101 JOHN YES
103 FINN YES
I have tried this oracle query but it is inserting data related to 102 ROLL_NO which I don't need
SELECT T1.ROLL_NO, T1.NAME,
CASE
WHEN T1.CODE <> 'ABC' THEN 'YES'
WHEN T1.CODE = 'ABC' AND T2.TOT_UNITS <> T1.AMOUNT THEN 'YES'
END RESULT
FROM (SELECT DISTINCT ROLL_NO, NAME, AMOUNT, CODE
FROM TABLE1 ) T1
JOIN (SELECT ROLL_NO, SUM(UNITS) AS TOT_UNITS
FROM TABLE1
GROUP BY ROLL_NO) T2 ON T1.ROLL_NO = T2.ROLL_NO
I am not able to figure out how to not insert ROLL_NO 102 record into TABLE2..Can anyone provide better query than this if possible? Thank you

A "better" option is to scan table1 only once.
SQL> insert into table2 (roll_no, name, result)
2 with temp as
3 (select roll_no, name, sum(units) sum_units, amount, code,
4 case when code = 'ABC' and sum(units) = amount then 'NO'
5 when code = 'ABC' and sum(units) <> amount then 'YES'
6 else 'YES'
7 end as result
8 from table1
9 group by roll_no, name, amount, code
10 )
11 select roll_no, name, result
12 from temp
13 where result = 'YES';
2 rows created.
SQL> select * from table2;
ROL NAME RES
--- ---- ---
101 JOHN YES
103 FINN YES
SQL>

Related

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>

Insert or update if already exists

merge into bonuses
using( select * from bonuses)s ON s.employee_id = '111'
WHEN MATCHED THEN update set bonus='555'
WHEN NOT MATCHED THEN insert insert into BONUSES (employee_id) values(115)
Table`s insert queries are
insert into BONUSES (employee_id) values(111)
insert into BONUSES (employee_id) values(112)
insert into BONUSES (employee_id) values(113)
insert into BONUSES (employee_id) values(114)
insert into BONUSES (employee_id) values(115)
If employee_id=111 already exists it should update else
it should insert.
Kindly help if someone know
Something like:
MERGE INTO bonuses dst
USING ( SELECT '111' AS employee_id, '555' AS bonus FROM DUAL ) src
ON ( dst.employee_id = src.employee_id )
WHEN MATCHED THEN
UPDATE SET bonus = src.bonus
WHEN NOT MATCHED THEN
INSERT ( employee_id, bonus )
VALUES ( src.employee_id, src.bonus );
Your statement has two syntax errors.
You have repeated the insert keyword.
You have missed the brackets around the on clause conditions. These are mandatory, unlike the join conditions in a normal from clause.
So your code should look like this:
merge into bonuses b
using( select * from bonuses) s
ON (s.employee_id = 115)
WHEN MATCHED THEN update set bonus='555'
WHEN NOT MATCHED THEN insert(employee_id) values(115)
/
However, it doesn't make sense to have the target table in the using clause. It doesn't produce the results you think it's going to...
SQL> select * from bonuses;
EMPLOYEE_ID BONUS
----------- ----------
111
112
113
114
115
5 rows selected.
SQL> merge into bonuses b
2 using( select * from bonuses) s
3 ON (s.employee_id = 115)
4 WHEN MATCHED THEN update set bonus='555'
5 WHEN NOT MATCHED THEN insert (employee_id) values(115)
6 /
9 rows merged.
SQL> select * from bonuses;
EMPLOYEE_ID BONUS
----------- ----------
111 555
112 555
113 555
114 555
115 555
115
115
115
115
9 rows selected.
SQL>
Maybe something like this would suit you?
merge into bonuses b
using( select * from employees) e
ON ( b.employee_id = e.employee_id )
WHEN MATCHED THEN
update set bonus= 555
WHEN NOT MATCHED THEN
insert (employee_id) values (e.id)
If you don't have a source of employee IDs distinct from the BONUSES table you can use the DUAL table to fake it:
SQL> merge into bonuses b
2 using( select 115 as employee_id, 555 as bonus from dual union all
3 select 116 as employee_id, 555 as bonus from dual) e
4 ON ( b.employee_id = e.employee_id )
5 WHEN MATCHED THEN
6 update set bonus= e.bonus
7 WHEN NOT MATCHED THEN
8 insert (employee_id) values (e.employee_id)
9 /
2 rows merged.
SQL> select * from bonuses;
EMPLOYEE_ID BONUS
----------- ----------
111
112
113
114
115 555
116
6 rows selected.
SQL>
I think what you're after is something like:
merge into bonuses tgt
using (select '111' employee_id, '555' bonus from dual) src
on (tgt.employee_id = src.employee_id)
WHEN MATCHED THEN
update set tgt.bonus = src.bonus
WHEN NOT MATCHED THEN
insert (tgt.employee_id, tgt.bonus)
values (src.employee_id, src.bonus);
As an aside, why are you inserting strings into columns which usually have a datatype of some form of NUMBER? Do these columns really have string datatypes (e.g. VARCHAR2, CHAR, etc)?

concatenate the output values in oracle plsql

create table item_value_tab
as
select 1110 Item_value,000394 bb_to_no, 55555 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000394 bb_to_no, 66666 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000394 bb_to_no, 77777 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000123 bb_to_no, 1111 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000124 bb_to_no, 2222 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000124 bb_to_no, 3333 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000011 bb_to_no, 75257 order_number, 'ABC' cust_no from dual
union all
select 1110 Item_value,000011 bb_to_no, 65257 order_number, 'ABC' cust_no from dual;
Take below code in Cursor 1
SELECT DISTINCT DECODE(nvl(Item_value,0),bb_to_no,null,'Item Value '||nvl(bb_to_no,0)||' Is not correct for order number '||order_number||' FOR Customer '||cust_no) vmsg
from item_value_tab;
Getting Output
Item Value 000394 Is not correct for order number 55555 FOR Customer ABC
Item Value 000394 Is not correct for order number 66666 FOR Customer ABC
Item Value 000394 Is not correct for order number 77777 FOR Customer ABC
Item Value 000123 Is not correct for order number 1111 FOR Customer ABC
Item Value 000124 Is not correct for order number 2222 FOR Customer ABC
Item Value 000124 Is not correct for order number 3333 FOR Customer ABC
Item Value 000011 Is not correct for order number 75257 FOR Customer ABC
Item Value 000011 Is not correct for order number 65257 FOR Customer ABC
-------------------------------------------------------------------------------
create table item_not_tab
as
select 0 item_id,53555 bb_to_no,1052 order_number,'AAA' cust_no from dual
union all
select 0 item_id,53655 bb_to_no,1138 order_number,'AAA' cust_no from dual;
Need to take the below code in cursor 2
select DECODE(nvl(item_id,0),0,'items not created for '||bb_to_no||'order number '||order_number||' FOR Customer '||cust_no,NULL) vmsg
from item_not_tab;
Getting Output
items not created for 53555 order number 1052 FOR Customer AAA
items not created for 53655 order number 1052 FOR Customer AAA
Expected output
Item Value Problems
Item Value 000394 Is not correct for order number 55555,66666,77777 FOR Customer ABC
Item Value 000123,000124 Is not correct for order number 1111 FOR Customer ABC
Item Value 000124 Is not correct for order number 2222,3333 FOR Customer ABC
Item Value 000011 Is not correct for order number 75257,65257 FOR Customer ABC
Items not found Problems
items not created for 53555,53655 order number 1052 FOR Customer AAA
note: please don't joins both tables in one cursor, I need to take 2 cursors. Both tables are same actually, but test case purpose I have as 2 d/f tables
oracle 11g 1.1 and 1.2
You need to first concatenate the tot_number inside the LOOP, and then use the value outside the LOOP.
For example,
SQL> SET serveroutput ON
SQL> DECLARE
2 v VARCHAR2(100);
3 BEGIN
4 FOR i IN
5 (SELECT 55555 str FROM dual
6 UNION
7 SELECT 66666 str FROM dual
8 UNION
9 SELECT 77777 str FROM dual
10 )
11 LOOP
12 v:= ltrim(v||','||i.str, ',');
13 END LOOP;
14 dbms_output.put_line('Output is concatenated '||v);
15 END;
16 /
Output is concatenated 55555,66666,77777
PL/SQL procedure successfully completed.
SQL>
Please Check the below QUERY :
SELECT DISTINCT o.bb_to_no,
(SELECT listagg(order_number,',') WITHIN GROUP (ORDER BY 1 desc)
FROM item_value_tab i WHERE o.bb_to_no = i.bb_to_no) AS total_num,
(SELECT DISTINCT(k.cust_no) FROM item_value_tab k
WHERE o.bb_to_no = k.bb_to_no) AS cust_name
FROM item_value_tab o
(OR)
EDIT : Please check this.
//It create collection of type table to store all the order_numbers
CREATE OR REPLACE TYPE t_varchar2_tab AS TABLE OF NUMBER;
// Below procedure will concatenate the list of order_numbers stored in
// the above created collection type.
CREATE OR REPLACE FUNCTION tab_to_string
(p_varchar2_tab IN t_varchar2_tab,
p_delimiter IN VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
l_string VARCHAR2(32767);
BEGIN
FOR i IN p_varchar2_tab.FIRST .. p_varchar2_tab.LAST LOOP
IF i != p_varchar2_tab.FIRST THEN
l_string := l_string || p_delimiter;
END IF;
l_string := l_string || p_varchar2_tab(i);
END LOOP;
RETURN l_string;
END tab_to_string;
SELECT bb_to_no,cust_no,
tab_to_string(CAST(COLLECT(order_number) AS t_varchar2_tab))
AS tot_number
FROM item_value_tab
GROUP BY bb_to_no,cust_no;
P.S : you can find more information on COLLECT() function on below link.
http://www.oracle-developer.net/display.php?id=306

How to assign a value to variable from select statement (PL/SQL Developer)

I'm working with PL/SQL Developer.
I'm trying to update values in a column(existing table).
The values used to populate rows should be auto incremented. The starting value is the maximum value that already exist in such field.
An example, I have the following table
ORDER_ID T_NAME T_PRICE
20 CAR 50
NULL VAN 100
NULL BIKE 10
NULL BOAT 300
After running the query I would expect the table to look like:
ORDER_ID T_NAME T_PRICE
20 CAR 50
21 VAN 100
22 BIKE 10
23 BOAT 300
The query I created so far is:
DECLARE
temp_order_id number;
BEGIN
:temp_order_id = SELECT ISNULL(MAX((ORDER_ID)),0) + 1 FROM SALES_ACC;
update SALES_ACC
set (ORDER_ID) = :temp_order_id , :temp_order_id = :temp_order_id + 1
where (ORDER_ID) is null;
END;
Oracle doesn't like assigning a value from select statement to the temp_order_id variable.
Does anyone has any idea how to fix it?
You don't need pl/sql for this - you can do it in a single update statement - eg:
create table test1 as
select 20 order_id, 'CAR' t_name, 50 t_price from dual union all
select null order_id, 'VAN' t_name, 100 t_price from dual union all
select null order_id, 'BIKE' t_name, 10 t_price from dual union all
select null order_id, 'BOAT' t_name, 300 t_price from dual;
update test1
set order_id = (select max(order_id) from test1) + rownum
where order_id is null;
commit;
select * from test1
order by 1;
ORDER_ID T_NAME T_PRICE
---------- ------ ----------
20 CAR 50
21 VAN 100
22 BIKE 10
23 BOAT 300
drop table test1;
As a side note, it sounds like order_id is something that should really be the primary key of the table - if you had that, then you wouldn't be allowed to add a row without a value. Plus, you would also need a sequence that you would then use when inserting data into the table - e.g.:
insert into test1 (order_id, t_name, t_price)
values (test1_seq.nextval, 'TRIKE', 30);
ORACLE's recomended way for this is either:
Create a sequence and a trigger on the table to assign order_id as soon as row is being inserted
or, for Oracle 12c, you can have an IDENTITY column
See How to create id with AUTO_INCREMENT on Oracle?, both approaches are described there.
Within the DECLARE ... BEGIN ... END; section you are in PL/SQL syntax. That is not equal to the SQL syntax. Within PL/SQL syntax you should make use of the so called select into statement.
SELECT ISNULL(MAX((ORDER_ID)),0) + 1
into :temp_order_id
FROM SALES_ACC

How to display comma separated descriptions based on comma separated values in Oracle 10g?

I am new to Oracle technology. Earlier I posted 2 posts for the same issue due to lack of understanding the requirement.
Table 1:
MSGID
-----
1,2,3
2,3
4
null
null
Table 2:
MID MSGDESC
---- -------
1 ONE
2 TWO
3 THREE
4 FOUR
Expected output:
XCOL DESC
----- -----
1,2,3 ONE,TWO,THREE
2,3 TWO,THREE
4 FOUR
I am not able to fulfil this requirement. Please provide me one solution.
Note: tables don't have any unique or primary key values. Table 1 has 5000 records and table 2 only has 80 records with descriptions.
create table Table1 (MSGID varchar2(100));
insert into Table1 values ('1,2,3');
insert into Table1 values ('2,3');
insert into Table1 values ('4');
insert into Table1 values (null);
insert into Table1 values (null);
create table Table2 (MID varchar2(100), MSGDESC varchar2(100));
insert into Table2 values ('1','ONE');
insert into Table2 values ('2','TWO');
insert into Table2 values ('3','THREE');
insert into Table2 values ('4','FOUR');
select
msgid as xcol,
"DESC",
col1, col2, ..., col12
from
Table1
left join (
select
msgid,
wm_concat(msgdesc) as "DESC"
from
(
select
msgid,
msgdesc
from
(select distinct msgid from Table1 where ...)
cross join (
select level as occ from dual connect by level <= 100)
)
left join Table2
on mid = regexp_substr(msgid, '[^,]+', 1, occ)
where
occ <= regexp_count(msgid, ',') + 1
order by msgid, occ
)
group by msgid
) using (msgid)

Resources