How to insert multiple values in table using subquery in Oracle? - sql

I have created two new tables TYPE and OPERATION-
TYPE table has the following columns
TYPE
(TYPE_ID : integer, with sequence
TYPE_NAME : String
BASE_ID :
)
The default values for TYPE_NAME are (Type1, Type2, Unknown) which needs to be added for every BASE_ID which is 68 rows in the BASE table
So there need to be 3 entries for every BASE_ID in the TYPE table
OPERATION table has the following columns
OPERATION
(OPERATION_ID : integer, with sequence
OPERATION_NAME : String
BASE_ID :
)
The default values for OPERATION_NAME are (Operation1, Operation2, Unknown) which needs to be added for every BASE_ID which is 68 rows in the BASE table
So there need to be 3 entries for every BASE_ID in the OPERATION table
Can someone please help me with a query so that I can perform this process of multiple entry with ease.
Thank you in advance.

Had to individually add query like this
INSERT INTO TYPE(TYPE_ID, TYPE_NAME, BASE_ID) (
select TYPE_SEQ.nextval, 'Type 1', ID_BASE FROM BASE);
INSERT INTO TYPE(TYPE_ID, TYPE_NAME, BASE_ID) (
select TYPE_SEQ.nextval, 'Type 2', ID_BASE FROM BASE);
INSERT INTO TYPE(TYPE_ID, TYPE_NAME, BASE_ID) (
select TYPE_SEQ.nextval, 'Unknown', ID_BASE FROM BASE);

CTE with cross join might help. Here's how.
Creating tables and a sequence first; my base table contains only 3 rows (as opposed to your 68 rows; just for simplicity. You don't have to create the base table as you already have it):
SQL> create table base as
2 select 1 base_id from dual union all
3 select 2 base_id from dual union all
4 select 3 base_id from dual;
Table created.
SQL> create sequence seqankit;
Sequence created.
SQL> create table type (type_id number, type_name varchar2(20), base_id number);
Table created.
SQL> create table operation (operation_id number, operation_name varchar2(20), base_id number);
Table created.
SQL>
Inserting into type and operation tables:
SQL> insert into type (type_id, type_name, base_id)
2 with names (type_name) as
3 (select 'type1' from dual union all
4 select 'type2' from dual union all
5 select 'unknown' from dual
6 )
7 select seqankit.nextval, n.type_name, b.base_id
8 from names n cross join base b;
9 rows created.
SQL> insert into operation (operation_id, operation_name, base_id)
2 with names (operation_name) as
3 (select 'operation1' from dual union all
4 select 'operation2' from dual union all
5 select 'unknown' from dual
6 )
7 select seqankit.nextval, n.operation_name, b.base_id
8 from names n cross join base b;
9 rows created.
SQL>
What's the result?
SQL> select * from type order by base_id, type_name;
TYPE_ID TYPE_NAME BASE_ID
---------- -------------------- ----------
1 type1 1
4 type2 1
7 unknown 1
2 type1 2
5 type2 2
8 unknown 2
3 type1 3
6 type2 3
9 unknown 3
9 rows selected.
SQL> select * from operation order by base_id, operation_name;
OPERATION_ID OPERATION_NAME BASE_ID
------------ -------------------- ----------
10 operation1 1
13 operation2 1
16 unknown 1
11 operation1 2
14 operation2 2
17 unknown 2
12 operation1 3
15 operation2 3
18 unknown 3
9 rows selected.
SQL>
Looks OK to me.

You can create a trigger that inserts the value for column TYPE_ID.
create trigger TYPE_INS
before insert on TYPE
for each row
when (new.TYPE_ID is null)
begin
:new.TYPE_ID := TYPE_SEQ.nextval;
end;
Then you don't need the TYPE_ID column in the INSERT statement, which allows you to do...
insert into TYPE (TYPE_NAME, BASE_ID)
select 'Type1', BASE_ID
from BASE
union
select 'Type2', BASE_ID
from BASE
union
select 'Unknown', BASE_ID
from BASE

Related

unpivot with a flag in Oracle

I have this table structure
ID,SUPPLIER_GROUP1,SUPPLIER1,SUPPLIER_GROUP2,SUPPLIER2.
i want to unpivot and get
ID,SUPPLIER_GROUP,SUPPLIER,TYPE
so each supplier_group and supplier values come to the appropriate column and in TYPE column will be either 1 or 2 to see if the SUPPLIER_GROUP and SUPPLIER value was supplier1 or supplier2 .
Use UNPIVOT with multiple column groups:
SELECT *
FROM table_name
UNPIVOT (
(supplier_group, supplier) FOR type IN (
(supplier_group1, supplier1) AS 1,
(supplier_group2, supplier2) AS 2
)
);
Which, for the sample data:
CREATE TABLE table_name (ID,SUPPLIER_GROUP1,SUPPLIER1,SUPPLIER_GROUP2,SUPPLIER2) AS
SELECT 1, 'sg1.1', 's1.1', 'sg2.1', 's2.1' FROM DUAL UNION ALL
SELECT 2, 'sg1.2', 's1.2', 'sg2.2', 's2.2' FROM DUAL UNION ALL
SELECT 3, 'sg1.3', 's1.3', 'sg2.3', 's2.3' FROM DUAL
Outputs:
ID
TYPE
SUPPLIER_GROUP
SUPPLIER
1
1
sg1.1
s1.1
1
2
sg2.1
s2.1
2
1
sg1.2
s1.2
2
2
sg2.2
s2.2
3
1
sg1.3
s1.3
3
2
sg2.3
s2.3
db<>fiddle here

How to store both integers and decimals in a column oracle [duplicate]

This question already has answers here:
Does Oracle store trailing zeroes for Number data type?
(3 answers)
Closed 11 months ago.
The community reviewed whether to reopen this question 11 months ago and left it closed:
Original close reason(s) were not resolved
I am trying to create a column (amount) that has both integers and decimals. But the issue is the column always stores the values as integers.
CREATE TABLE payments(payment_id , Status , payment_date , account_id , currency, amount) AS
SELECT '72b30af0-323e-4931-8fcc-2c08ad8d0b19', 'completed', TO_DATE ('01/10/2017','DD/MM/YYYY'), 2291969088, 'GBP', CAST(10.00 AS NUMBER(20,18)) FROM DUAL UNION ALL
SELECT '1b5341c0-508c-450f-a139-bc898f112fed', 'completed', TO_DATE ('12/11/2014','DD/MM/YYYY'), 7851880663, 'USD', CAST(20 AS NUMBER) FROM DUAL UNION ALL
SELECT '4c8eb68d-3085-4500-b735-371bb7e1ac97','submitted', TO_DATE ('03/07/2016','DD/MM/YYYY'), 5326844767, 'USD', CAST(3.000 AS NUMBER) FROM DUAL UNION ALL
SELECT '33825ef2-d0da-4062-a435-b74a25a850ed','failed', TO_DATE ('19/01/2017','DD/MM/YYYY'), 3668657617, 'EUR', CAST(40 AS NUMBER) FROM DUAL UNION ALL
SELECT '45c10898-d668-4ad1-9730-415254f6e085', 'completed', TO_DATE ('10/05/2017','DD/MM/YYYY'), 9040142052, 'GBP', CAST(30.000 AS NUMBER) FROM DUAL
I have tried using Number alone and Number with precision and scale but the result is the same even with the Decimal data type. Not sure what am I doing wrong here?
The table will store the values in a correct way.
Your select is the problem I believe.
select payment_id
, Status
, payment_date
, account_id
, currency
, to_char(amount, '99.999')
from payments;
I have used to_char() functionto format your column when selecting.
Please correct me if I am wrong.
DEMO
Just to expand on answer by #VBoka, providing more thorough example:
the root of your question is basic math. Trailing zeros to the right of the decimal are insignificant. 10 = 10.0 = 10.000000. You are confusing how the value is stored vs how it is displayed by default.
SQL> -- -------- create the tables
SQL> create table my_demo (my_id integer,
2 my_value number(5,2));
Table created.
SQL> -- -------- load tables
SQL> insert into my_demo values (1,10);
1 row created.
SQL> insert into my_demo values (2,10.0);
1 row created.
SQL> insert into my_demo values (3,010.00);
1 row created.
SQL> -- -------- Do the query
SQL> select my_id,
2 my_value,
3 to_char(my_value,'999.999') formatted_value
4 from my_demo
5 order by my_id
6 ;
MY_ID MY_VALUE FORMATTE
---------- ---------- --------
1 10 10.000
2 10 10.000
3 10 10.000
3 rows selected.
And why are you using "CAST(10.00 AS NUMBER"? The 10.00 (without quotes) is already a number. If you were to enclose it in single quotes ("CAST('10.00' AS NUMBER"), then it would be a string that needs to be treated with either CAST or TO_NUMBER.
== new demo for getting just integer values
SQL> -- -------- load tables
SQL> insert into my_demo values (1,10);
1 row created.
SQL> insert into my_demo values (2,10.0);
1 row created.
SQL> insert into my_demo values (3,010.10);
1 row created.
SQL> -- -------- Do the query
SQL> select my_id,
2 my_value,
3 to_char(my_value,'999.999') formatted_value
4 from my_demo
5 order by my_id
6 ;
MY_ID MY_VALUE FORMATTE
---------- ---------- --------
1 10 10.000
2 10 10.000
3 10.1 10.100
3 rows selected.
SQL> --
SQL> select my_id,
2 my_value,
3 to_char(my_value,'999.999') formatted_value
4 from my_demo
5 where my_value = trunc(my_value)
6 order by my_id
7 ;
MY_ID MY_VALUE FORMATTE
---------- ---------- --------
1 10 10.000
2 10 10.000
2 rows selected.

Oracle function return table

I don't know what is best solution for my problem. I need function with one parameter which resault is
VAL
-----
1
2
3
In function I need put union all to get all value.
Select column_1 as VAL from my_table where id = P_FUNCTION_PARAMETER --return 1
union all
Select column_2 as VAL from my_table where id = P_FUNCTION_PARAMETER --return 2
union all
Select column_3 as VAL from my_table where id = P_FUNCTION_PARAMETER; --return 3
What is the best solution for this?
"Best" just depends. Return a ref cursor or a collection, whichever you prefer.
For example:
SQL> create or replace function f_test_rc
2 return sys_refcursor
3 is
4 rc sys_refcursor;
5 begin
6 open rc for
7 select 1 from dual union all
8 select 2 from dual union all
9 select 3 from dual;
10
11 return rc;
12 end;
13 /
Function created.
SQL> select f_test_rc from dual;
F_TEST_RC
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
1
----------
1
2
3
SQL> create or replace function f_test_coll
2 return sys.odcinumberlist
3 as
4 l_coll sys.odcinumberlist;
5 begin
6 select * bulk collect into l_coll
7 from (select 1 from dual union all
8 select 2 from dual union all
9 select 3 from dual
10 );
11
12 return l_coll;
13 end;
14 /
Function created.
SQL> select * from table(f_test_coll);
COLUMN_VALUE
------------
1
2
3
SQL>
First let's set up a small table for testing:
create table my_table
( id number primary key
, column_1 number
, column_2 number
, column_3 number
);
insert into my_table
select 1008, 3, -8, 0.2 from dual union all
select 1002, 6, null, -1.2 from dual
;
commit;
The function can look like this. Note that I don't use union all - that will require reading the table three times, when only one time is enough.
create or replace function my_function (p_function_parameter number)
return sys.odcinumberlist
as
arr sys.odcinumberlist;
begin
select case ord when 1 then column_1
when 2 then column_2
when 3 then column_3 end
bulk collect into arr
from my_table cross join
(select level as ord from dual connect by level <= 3)
where id = p_function_parameter
order by ord
;
return arr;
end;
/
The function could be used, for example, like this: (in older versions you may need to wrap the function call within the table operator)
select * from my_function(1002);
COLUMN_VALUE
------------
6
-1.2

Rows to Columns - Oracle - Not using Union ALL

Is there any better way achieve the below result other than using union all?
The table has millions of records, so looking for a better option where the result set is fetched once.
create table test_tab (
rec_id number(3),
p_code varchar2(5),
q_code varchar2(5),
r_code varchar2(5),
p_amt number(8),
q_amt number(8),
r_amt number(8)
);
delete from test_tab;
insert into test_tab (rec_id, p_code, q_code,r_code , p_amt,q_amt,r_amt)
values (1, 'p1','q1','r1',18,9,9);
insert into test_tab (rec_id, p_code, q_code,r_code , p_amt,q_amt,r_amt)
values (2, 'p2','q2','r2',28,6,4);
insert into test_tab (rec_id, p_code, q_code,r_code , p_amt,q_amt,r_amt)
values (3, 'p1',null,null,18,null,null);
insert into test_tab (rec_id, p_code, q_code,r_code , p_amt,q_amt,r_amt)
values (4, null,'q3','r3',null,9,9);
commit;
select rec_id, p_code,p_amt from test_tab where p_code is not null
union all
select rec_id, q_code,q_amt from test_tab where q_code is not null
union all
select rec_id, r_code,r_amt from test_tab where r_code is not null;
Result:
REC_ID
P_CODE
P_AMT
1
q1
9
1
p1
18
1
r1
9
2
p2
28
2
q2
6
2
r2
4
3
p1
18
4
q3
9
4
r3
9
This is a basic application of the unpivot operator, available since Oracle 11.1.
select rec_id, code, amt
from test_tab
unpivot ((code, amt) for ord in
((p_code, p_amt) as 1, (q_code, q_amt) as 2, (r_code, r_amt) as 3))
order by rec_id, ord -- if needed
;
REC_ID CODE AMT
---------- ----- ----------
1 p1 18
1 q1 9
1 r1 9
2 p2 28
2 q2 6
2 r2 4
3 p1 18
4 q3 9
4 r3 9
9 rows selected.
Notice a few things. I call the output columns code and amt - it makes no sense to have the prefix p_ in the output column names. Also, "exclude nulls" is the default in unpivot, so I didn't need to mention it explicitly (although it wouldn't hurt anything). Finally, while perhaps not critical, I also created a column ord to reflect column order, and ordered the rows in the output in the same order as you had the columns in the input.
You can use Hiearchy query and cross join as follows:
select * from (select rec_id,
case lvl when 1 then p_code when 2 then q_code else r_code end as p_code,
case lvl when 1 then p_amt when 2 then q_amt else r_amt end as p_amount
from test_tab
cross join (select level as lvl from dual connect by level <= 3) )
where p_code is not null
You can use a lateral join:
select x.*
from test_tab t cross join lateral
(select t.rec_id, t.p_code as code, t.p_amount as amount from dual union all
select t.rec_id, t.q_code, t.q_amount from dual union all
select t.rec_id, t.r_code, t.r_amount from dual
) x
where code is not null;
Technical, this still has a union all, but it is only scanning the original table once.

rows convert in oracle sql

I have values like below
1,a,b,c
2,d,e
3,f,g
Expected output
1 a
1 b
1 c
2 d
2 e
Can you please help me?
It is very much close to implementing the logic to Split comma delimited strings in a table. The only tricky thing is that you have the row number along with the string itself.
You could use ROWNUM as pseudo column, and then filter out those rows where the leading substr of the string is repeating with the ROWNUM.
For example,
Setup
SQL> CREATE TABLE t(text VARCHAR2(4000));
Table created.
SQL>
SQL> INSERT INTO t SELECT '1,a,b,c' text FROM dual;
1 row created.
SQL> INSERT INTO t SELECT '2,d,e' text FROM dual;
1 row created.
SQL> INSERT INTO t SELECT '3,f,g' text FROM dual;
1 row created.
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT * FROM t;
TEXT
----------
1,a,b,c
2,d,e
3,f,g
SQL>
Solution:
SQL> WITH DATA AS(
2 SELECT ROWNUM rn, text FROM t
3 )
4 SELECT *
5 FROM
6 (SELECT rn,
7 trim(regexp_substr(t.text, '[^,]+', 1, lines.COLUMN_VALUE)) text
8 FROM DATA t,
9 TABLE (CAST (MULTISET
10 (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(t.text, ',')+1
11 ) AS sys.odciNumberList ) ) lines
12 )
13 WHERE TO_CHAR(rn) <> text
14 ORDER BY rn
15 /
RN TEXT
---------- ----------
1 a
1 b
1 c
2 d
2 e
3 f
3 g
7 rows selected.
SQL>