Oracle: split function result into multiple columns - oracle

I have a package in oracle. In the package i have a procedure which performs an (insert into ..select.. ) statement
which is like this:
insert into some_table(col1 , col2 , col3, col4)
select col1 , col2, my_func(col3) as new_col3 , col4
from some_other_table
my_func(col3) does some logic to return a value.
now i need to to return two values instead of one, using the same logic.
i can simply write another function to do the same logic and return the second value, but that would be expensive because the function selects from a large history table.
i can't do a join with the history table because the function doesn't perform a simple select.
is there a way to get two columns by calling this function only once?

Create an OBJECT type with two attributes and return that from your function. Something like:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TYPE my_func_type IS OBJECT(
value1 NUMBER,
value2 VARCHAR2(4000)
);
/
CREATE FUNCTION my_func
RETURN my_func_type
IS
value my_func_type;
BEGIN
value := my_func_type( 42, 'The Meaning of Life, The Universe and Everything' );
RETURN value;
END;
/
CREATE TABLE table1 (col1, col2, col5 ) AS
SELECT 1, 2, 5 FROM DUAL
/
Query 1:
SELECT col1,
col2,
t.my_func_value.value1 AS col3,
t.my_func_value.value2 AS col4,
col5
FROM (
SELECT col1,
col2,
my_func() AS my_func_value,
col5
FROM table1
) t
Results:
| COL1 | COL2 | COL3 | COL4 | COL5 |
|------|------|------|--------------------------------------------------|------|
| 1 | 2 | 42 | The Meaning of Life, The Universe and Everything | 5 |

Related

converting single column to equal rows in Oracle

I have a requirement to display one column in a matrix table.
ex:
Select SlotNumber from Parking_lot_table;
out:
SL01
SL02
SL03
SL04
SL05
SL06
SL07
SL08
SL09
SL10
My Output must be like :
Col1 Col2 Col3 Col4 Col5
SL01 SL02 SL03 SL04 SL05
SL06 SL07 SL08 SL09 SL10
even Its fine to fix the number of columns ...
Kindly suggest ... How to do this in Oracle SQL
select * from
( select trunc((rownum -1) / 5 ) gr , mod(rownum, 5) rn, slot
from
( select * from
parking_lot_table order by to_number(REGEXP_REPLACE(slot, '[^0-9]+', ''))
)
)
pivot
( max(slot)
for rn in ( 1 as Col1, 2 as Col2, 3 as Col3, 4 as Col4, 0 as Col5) )
order by 1

How to split two columns data in to two rows apart from using union? [duplicate]

I have 50 column in a table and it returns only one row and I want that one row with 50 column to be displayed in 50 rows and one column.
Can any one suggest me the Oracle query for it?
You can use UNPIVOT for one row like this to get only column with values
SELECT colvalue
FROM
(
SELECT *
FROM Table1
UNPIVOT INCLUDE NULLS
(
colvalue FOR cols IN (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, ... col50)
)
);
Sample output:
| COLVALUE |
------------
| 1 |
| 2 |
| (null) |
|..........|
If you need column with column names from your pivoted table just ditch the outer select
SELECT *
FROM Table1
UNPIVOT INCLUDE NULLS
(
colvalue FOR cols IN (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, ... col50)
);
Sample output:
| COLS | COLVALUE |
--------------------
| COL1 | 1 |
| COL2 | 2 |
| COL3 | (null) |
| ..... |......... |
Here is SQLFiddle demo
Be prepared for a lot of typing :) Oracle has UNPIVOT functionality but it wants at least two columns in the result, so it won't work for your situation.
First off, you'll need a counter from 1 to 50. You can query one like this:
SELECT LEVEL as Counter FROM DUAL CONNECT BY LEVEL <= 50
If you execute this query you'll get the numbers 1-50 as your result. With that as a basis, here's the full(ish) query:
WITH Cols AS (
SELECT LEVEL as Counter
FROM DUAL
CONNECT BY LEVEL <= 50
)
SELECT
CASE Cols.Counter
WHEN 1 THEN Col1
WHEN 2 THEN Col2
WHEN 3 THEN Col3
. . .
WHEN 50 THEN Col50
END AS myColumn
FROM myTable
CROSS JOIN Cols
ORDER BY Cols.Counter
Note that all of the columns must be the same data type, so if you have a mixture of character, number and date you'll need to convert them all to character.
Note that this query assumes one row in the table, as mentioned in the question. If there's more than one row you should end with ORDER BY a-column-that-identifies-the-row, Cols.Counter.

Select rows with same id without nulls and one row with Null if multiple nulls are present

I want to get only rows having a value and some other value than NULL for a particular username column.
If both rows have null for that particular username then it should show Null only once in output. If there are more than two rows for same username with null and some other value then display the value only not null.
Below is example sample and output. How it can be done using sql query?
Table:
Col1 | Col2
-------------------------
a | abc
a | bc
b | null
b | null
c | der
c | null
Output:
Col1 | Col2
-------------------------
a | abc
a | bc
b | null
c | der
Outlining the idea, there might be some syntax errors, don't have access to oracle.
SELECT * FROM
( SELECT DISTINCT USERNAME FROM <TABLE> ) USERS
LEFT OUTER JOIN
( SELECT USERNAME, COL2 FROM <TABLE> WHERE COL2 IS NOT NULL) USERS_COL2
ON
USRES.USERNAME = USERS_COL2.USERNAME
you use listagg () or stragg ()
drop table test;
create table test (
col1 varchar2(10),
col2 varchar2(10)
);
insert into test values ( 'a','abc');
insert into test values ( 'a','abc');
insert into test values ( 'b',null);
insert into test values ( 'b',null);
insert into test values ( 'c','der');
insert into test values ( 'c',null);
commit;
select col1,
listagg (col2,',') within group (order by col1) col2
from test
group by col1;
COL1 COL2
---------- -----------
a abc,abc
b
c der
select col1, stragg (col2)
from test
group by col1;
select col1, col2, count(*)
from omc.test
group by col1,col2;
you can remove count(*)

Insert data into multiple table from one table using a procedure [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have one parent table which consists of around 150 columns. I need to get the records from the parent table and insert them into 11 different child tables, which have the column names and data types.
Oracle has a very convenient INSERT ALL command that can help in this case.
The syntax of unconditional version is:
INSERT ALL
INTO child1( col1, col2, col3 ) VALUES( col1, col2, col3 )
INTO child2 VALUES( col1, col2, col3 )
INTO child3 ( col1, col2, col3 )
INTO child4
SELECT col1, col2, col3
FROM parent
-- WHERE some conditions;
A link to a demo: --> http://sqlfiddle.com/#!4/3eb62/1
The above command retrieves all rows from the parent table using SELECT ... FROM ... (at the bottom), then, for each retrieved record, it executes all INSERT ... statements.
If the SELECT clause has also a WHERE conditions clause, then only rows that meet these conditions will be inserted.
The INSERT part of the query in the example could have various forms:
A full form with explicitely definied columns of source and destination tables:
INTO dest_table( destcol1, ... destcolN ) VALUES (sourcecol1, ..., sourcecolN)
A shortened form where only columns from source table are given
INTO dest_table VALUES (sourcecol1, ..., sourcecolN)
Another shortened form where only columns from destination table are given
INTO dest_table( destcol1, ... destcolN )
or the simplest:
INTO dest_table
INSERT ALL has also a conditional version:
INSERT ALL
WHEN 1=1 THEN INTO child1( col1, col2, col3 ) VALUES( col1, col2, col3 )
WHEN col1 <> 2 THEN INTO child2 VALUES( col1, col2, col3 )
WHEN col3 < 3 THEN INTO child3 ( col1, col2, col3 )
WHEN col2 = 'rec 3' THEN INTO child4
SELECT col1, col2, col3
FROM parent;
A link to a demo: ---> http://sqlfiddle.com/#!4/e7da3/1
This version inserts rows only when a condition specified after WHEN clause is meet.For each selected rows always all conditions are evaluated.
There is also another conditional form: INSERT FIRST
INSERT FIRST
WHEN col1 >= 4 THEN INTO child1( col1, col2, col3 ) VALUES( col1, col2, col3 )
WHEN col1 >= 3 THEN INTO child2 VALUES( col1, col2, col3 )
WHEN col1 >= 2 THEN INTO child3 ( col1, col2, col3 )
WHEN col1 >= 1 THEN INTO child4
SELECT col1, col2, col3
FROM parent;
A link to a demo: http://sqlfiddle.com/#!4/a421e/1
Here, for each source row, Oracle evaluates conditions from top to bottom, and when some condition is true, then executes only this one INSERT statement, and skips remaining inserts.
------- EDIT -------
An example how to do it in a procedural way:
CREATE OR REPLACE PROCEDURE name
AS
BEGIN
INSERT ALL
INTO child1( col1, col2, col3 ) VALUES( col1, col2, col3 )
INTO child2 VALUES( col1, col2, col3 )
INTO child3 ( col1, col2, col3 )
INTO child4
SELECT col1, col2, col3
FROM parent ;
-- if commit is required, place it here
-- COMMIT;
END;
/

Oracle query to convert multiple column into one column

I have 50 column in a table and it returns only one row and I want that one row with 50 column to be displayed in 50 rows and one column.
Can any one suggest me the Oracle query for it?
You can use UNPIVOT for one row like this to get only column with values
SELECT colvalue
FROM
(
SELECT *
FROM Table1
UNPIVOT INCLUDE NULLS
(
colvalue FOR cols IN (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, ... col50)
)
);
Sample output:
| COLVALUE |
------------
| 1 |
| 2 |
| (null) |
|..........|
If you need column with column names from your pivoted table just ditch the outer select
SELECT *
FROM Table1
UNPIVOT INCLUDE NULLS
(
colvalue FOR cols IN (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, ... col50)
);
Sample output:
| COLS | COLVALUE |
--------------------
| COL1 | 1 |
| COL2 | 2 |
| COL3 | (null) |
| ..... |......... |
Here is SQLFiddle demo
Be prepared for a lot of typing :) Oracle has UNPIVOT functionality but it wants at least two columns in the result, so it won't work for your situation.
First off, you'll need a counter from 1 to 50. You can query one like this:
SELECT LEVEL as Counter FROM DUAL CONNECT BY LEVEL <= 50
If you execute this query you'll get the numbers 1-50 as your result. With that as a basis, here's the full(ish) query:
WITH Cols AS (
SELECT LEVEL as Counter
FROM DUAL
CONNECT BY LEVEL <= 50
)
SELECT
CASE Cols.Counter
WHEN 1 THEN Col1
WHEN 2 THEN Col2
WHEN 3 THEN Col3
. . .
WHEN 50 THEN Col50
END AS myColumn
FROM myTable
CROSS JOIN Cols
ORDER BY Cols.Counter
Note that all of the columns must be the same data type, so if you have a mixture of character, number and date you'll need to convert them all to character.
Note that this query assumes one row in the table, as mentioned in the question. If there's more than one row you should end with ORDER BY a-column-that-identifies-the-row, Cols.Counter.

Resources