rows convert in oracle sql - 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>

Related

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

Oracle, inserting rows by using Max+1 of the existing field

Hi I am pretty new to oracle.
I have to insert a row using a value of (max + 1) from the existing field.
Does anyone has any idea on how to achieve that?
Do you mean like this?
SQL> create table t (col) as (select 4 from dual union all select 9 from dual);
Table created.
SQL> select * from t;
COL
----------
4
9
2 rows selected.
SQL> insert into t values (1 + (select max(col) from t));
1 row created.
SQL> select * from t;
COL
----------
4
9
10
3 rows selected.

How to reverse the string 'ab,cd,ef' to 'ef->cd->ab'

when I select the table from Oracle, I want to handle one col'val :
eg:
'ab,cd,ef' to 'ef->cd->ab';
'AB,BC' to 'BC->AB';
'ACNN,BBCCAC' to 'BBCCAC->ACNN';
'BBBDC,DCCX,FFF' to 'FFF->DCCX->BBBDC'
We have two tasks. The first is to tokenize the original strings. This is quite easy with regular expressions (although there are more performant approaches if you are dealing with large volumes). The second task is to re-assemble the tokens in reverse order; we can use the 11gR2 LISTAGG() function for this:
with tokens as (
select distinct col1, regexp_substr(col1, '[^,]+', 1, level) as tkn, level as rn
from t23
connect by level <= regexp_count (col1, '[,]') +1
)
select col1
, listagg(tkn, '->')
within group (order by rn desc) as rev_col1
from tokens
group by col1
/
Here is a SQL Fiddle.
You can do it with a mix of string split and string aggregation.
Using:
REGEXP_SUBSTR : To split the comma delimited string into rows
LISTAGG : To aggregate the values
You can have a look at this article to understand how string split works http://lalitkumarb.wordpress.com/2015/03/04/split-comma-delimited-strings-in-a-table-using-oracle-sql/
SQL> WITH DATA AS(
2 SELECT 1 ID, 'ab,cd,ef' text FROM dual UNION ALL
3 SELECT 2 ID, 'AB,BC' text FROM dual UNION ALL
4 SELECT 3 ID, 'ACNN,BBCCAC' text FROM dual
5 )
6 SELECT ID,
7 listagg(text, ',') WITHIN GROUP (
8 ORDER BY rn DESC) reversed_indices
9 FROM
10 (SELECT t.id,
11 rownum rn,
12 trim(regexp_substr(t.text, '[^,]+', 1, lines.COLUMN_VALUE)) text
13 FROM data t,
14 TABLE (CAST (MULTISET
15 (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(t.text, ',')+1
16 ) AS sys.odciNumberList ) ) lines
17 ORDER BY ID
18 )
19 GROUP BY ID
20 /
ID REVERSED_INDICES
---------- ------------------------------
1 ef,cd,ab
2 BC,AB
3 BBCCAC,ACNN
SQL>
Let's say your table looks like:
SQL> SELECT * FROM t;
ID TEXT
---------- ------------------------------
1 ab,cd,ef
2 AB,BC
3 ACNN,BBCCAC
4 word1,word2,word3
5 1,2,3
SQL>
Using the above query:
SQL> SELECT ID,
2 listagg(text, '-->') WITHIN GROUP (
3 ORDER BY rn DESC) reversed_indices
4 FROM
5 (SELECT t.id,
6 rownum rn,
7 trim(regexp_substr(t.text, '[^,]+', 1, lines.COLUMN_VALUE)) text
8 FROM t,
9 TABLE (CAST (MULTISET
10 (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(t.text, ',')+1
11 ) AS sys.odciNumberList ) ) lines
12 ORDER BY ID
13 )
14 GROUP BY ID
15 /
ID REVERSED_INDICES
---------- ------------------------------
1 ef-->cd-->ab
2 BC-->AB
3 BBCCAC-->ACNN
4 word3-->word2-->word1
5 3-->2-->1
SQL>

Get next row value based on returned list of rows

In Oracle, suppose I have a query that returns the following list:
ID Sequence#
12 1
15 3
25 5
All I know in this case is the ID of some row (let's suppose 12), I need to return the ID of a row with the next sequence number which in this case is 3 (id = 15)
How can I do it? I know there's a Oracle function lead, but I wasn't able to successfully impement is.
Yes, you can use lead function to get the next value. Here is an example of how it can be done.
-- sample of data from your question
SQL> with t1(ID, Sequence#) as
2 (
3 select 12, 1 from dual union all
4 select 15, 3 from dual union all
5 select 25, 5 from dual
6 )
7 select *
8 from (select id
9 , sequence#
10 , lead(sequence#) over(order by id) next_sequence#
11 , lead(id) over(order by id) next_id#
12 from t1
13 )
14 where id = 12
15 ;
ID SEQUENCE# NEXT_SEQUENCE# NEXT_ID#
---------- ---------- -------------- ----------
12 1 3 15
SELECT * FROM table1 where ID in (SELECT min(ID) FROM table1 WHERE ID > 12)
Select sequence from my_ table where id=(select min(id) from my_table where sequence> 1)
Replace (1) in the above query with any value that you are searching for its next