PL/SQL ORACLE query as Result - oracle

How to write SQL Query for below condition
Result must be in PL/SQL Query:
MY_TABLE and data is Like bellow:
| sl. no | col1 | col2 | col3 |col4 | col5 ---col30| col41|col42|....col50
+------ +------+------ +------ +------+
| 1001 | 50 | 101 | 12 | 40 |
| 1002 | 30 | 250 | 80 | |
| 1003 | 40 | 150 | 90 | |
| 1004 | 50 | 250 | 20 | |
| 1005 | 70 | 300 | 30 | 50 |
| 1006 | 80 | 400 |
col1, col2,col3,...col30
I want to retrieve col1..to col30 data(value) against sl.no (where condition is sl.no) if col data is available. Oracle 9I
as row wise
only in PL/SQL oracle 9i
result like:
1001 | 50
1001 | 101
1001 | 12
1001 | 40
1002 | 30
1002 |250
1002 | 80
1003 | 40
1003 | 150
1003 | 90
1004 | 50
1004 | 250
1004 | 20
1005 |70
1005 |300
1005 |30
1005 |50
1006 |80
1006 |400

select *
from (
select no, decode( rn, 1, col1, 2, col2, 3, col3, 4, col4, 5, col5, ...., 30, col30) col
from table_name, (select rownum rn from all_objects where rownum <= 30 )
)
where col is not null
or
select *
from (
select no, decode( rn, 1, col1, 2, col2, 3, col3, 4, col4, 5, col5, ...., 30, col30) col
from table_name, (select rownum rn from dual connect by rownum <= 30 )
)
where col is not null
the second one is better but I don't remember will it works in 9i or not

To unpivot the pre-11g way, you would need to do something like:
WITH my_table AS (SELECT 1001 sl_no, 50 col1, 101 col2, 12 col3, 40 col4 FROM dual UNION ALL
SELECT 1002 sl_no, 30 col1, 250 col2, 80 col3, NULL col4 FROM dual UNION ALL
SELECT 1003 sl_no, 40 col1, 150 col2, 90 col3, NULL col4 FROM dual UNION ALL
SELECT 1004 sl_no, 50 col1, 250 col2, 20 col3, NULL col4 FROM dual UNION ALL
SELECT 1005 sl_no, 70 col1, 300 col2, 30 col3, 50 col4 FROM dual UNION ALL
SELECT 1006 sl_no, 80 col1, 400 col2, NULL col3, NULL col4 FROM dual),
dummy AS (SELECT LEVEL lvl
FROM dual
CONNECT BY LEVEL <= 4 -- number of columns to unpivot
),
results AS (SELECT mt.sl_no,
d.lvl,
CASE WHEN d.lvl = 1 THEN 'COL1'
WHEN d.lvl = 2 THEN 'COL2'
WHEN d.lvl = 3 THEN 'COL3'
WHEN d.lvl = 4 THEN 'COL4'
END col_name,
CASE WHEN d.lvl = 1 THEN col1
WHEN d.lvl = 2 THEN col2
WHEN d.lvl = 3 THEN col3
WHEN d.lvl = 4 THEN col4
END col_value
FROM my_table mt
CROSS JOIN dummy d)
SELECT sl_no,
col_name,
col_value
FROM results
WHERE col_value IS NOT NULL
ORDER BY sl_no, lvl;
SL_NO COL_NAME COL_VALUE
---------- -------- ----------
1001 COL1 50
1001 COL2 101
1001 COL3 12
1001 COL4 40
1002 COL1 30
1002 COL2 250
1002 COL3 80
1003 COL1 40
1003 COL2 150
1003 COL3 90
1004 COL1 50
1004 COL2 250
1004 COL3 20
1005 COL1 70
1005 COL2 300
1005 COL3 30
1005 COL4 50
1006 COL1 80
1006 COL2 400
The dummy subquery is used to generate a set of rows that is the same number as the number of columns to be unpivoted. In your example, it's 4.
We then cross join that to the table - this means each row in the table is duplicated 4 times - one for each column to be unpivoted.
Once we have that, we say "display the first column to be unpivoted on the first row, the second column on the second row, the third column on the third row, etc..."
I've also included a column which lists the column name that the corresponding value came from; I know you didn't ask for this info in your question, but it's usually required, and easy enough to produce.
Once we have unpivoted the columns, we then remove any values that are null.

Related

how to check length of "concatenate" string

Has anybody an idea how to write a query in Oracle to get length of characters:
| user | action |
-------------------------
| mary | aaa | # 3 characters from action
| mary | bbbbb | # 5 characters from action
| mary | c | # 1 character from action
| adam | xx | # 2 characters from action
| adam | yyyy | # 4 characters from action
| adam | zzzzzzz | # 7 characters from action
So in result should be sum of characters for each:
| mary | 9 |
| adam | 13 |
Thanks.
SUM + LENGTH along with GROUP BY user. Sample data in lines #1 - 14; query you need begins at line #15.
SQL> WITH
2 test (cuser, action)
3 AS
4 (SELECT 'mary', 'aaa' FROM DUAL
5 UNION ALL
6 SELECT 'mary', 'bbbbb' FROM DUAL
7 UNION ALL
8 SELECT 'mary', 'c' FROM DUAL
9 UNION ALL
10 SELECT 'adam', 'xx' FROM DUAL
11 UNION ALL
12 SELECT 'adam', 'yyyy' FROM DUAL
13 UNION ALL
14 SELECT 'adam', 'zzzzzzz' FROM DUAL)
15 SELECT cuser, SUM (LENGTH (action))
16 FROM test
17 GROUP BY cuser;
CUSE SUM(LENGTH(ACTION))
---- -------------------
mary 9
adam 13
SQL>
Use the LENGTH function in your aggregation:
SELECT "USER",
SUM( LENGTH( action ) ) AS total_length
FROM table_name
GROUP BY "USER"
Which, for your sample data:
CREATE TABLE table_name( "USER", action ) AS
SELECT 'mary', 'aaa' FROM DUAL UNION ALL
SELECT 'mary', 'bbbbb' FROM DUAL UNION ALL
SELECT 'mary', 'c' FROM DUAL UNION ALL
SELECT 'adam', 'xx' FROM DUAL UNION ALL
SELECT 'adam', 'yyyy' FROM DUAL UNION ALL
SELECT 'adam', 'zzzzzzz' FROM DUAL;
Outputs:
USER | TOTAL_LENGTH
:--- | -----------:
mary | 9
adam | 13
db<>fiddle here

A scenario for combining multiple rows in oracle

I have a table with vaues like
MY_ID(NUMBER) COL_1(NUMBER) COL_2(NUMBER) COL_3(VARCHAR2)
11 1001 NULL GT
11 NULL 1002 TG
11 NULL 1003 TG2
12 1004 NULL GT
12 NULL 1006 TG
12 NULL 1005 TG2
My expected result is
MY_ID(NUMBER) COL_1(NUMBER) COL_2(NUMBER) COL_3(VARCHAR2)
11 1001 1003 TG2
12 1004 1006 TG
I can use MAX for numbers, but how about the Varchar2?
How can I combine multiple rows like this?
MAX aggregate functions can be used for varchar too, see this example:
SELECT my_id, max( col_1 ), max( col_2 ), max( col_3 )
FROM Table1
GROUP BY my_id;
Demo: http://sqlfiddle.com/#!4/406e8d7/6
| MY_ID | MAX(COL_1) | MAX(COL_2) | MAX(COL_3) |
|-------|------------|------------|------------|
| 11 | 1001 | 1003 | TG2 |
| 12 | 1004 | 1006 | TG2 |
However, in your question is stated that for the record 12 must be returned value TG instead TG2. I'm guessing that you want to return not the maximum column value of COL_3, but the value from the record for which the maximum value from column COL2 exists. In such a case you can use a query like this:
SELECT my_id, max( col_1 ), max( col_2 ),
max( col_3 ) KEEP (DENSE_RANK LAST ORDER BY col_2 NULLS FIRST)
FROM Table1
GROUP BY my_id;
Demo: http://sqlfiddle.com/#!4/406e8d7/6
| MY_ID | MAX(COL_1) | MAX(COL_2) | MAX(COL_3)KEEP(DENSE_RANKLASTORDERBYCOL_2NULLSFIRST) |
|-------|------------|------------|------------------------------------------------------|
| 11 | 1001 | 1003 | TG2 |
| 12 | 1004 | 1006 | TG |

repeat rows in a given sequence format

I have a table with following data
Order_no | Part_No | R_from | R_to
1001 | 1010037-00L| 1 | 5
1001 | 1010025-00L| 6 | 12
I need to get the above data to a report in below manner.
R_NO | PART_NO
------------------
1 | 1010037-00L
2 | 1010037-00L
3 | 1010037-00L
4 | 1010037-00L
5 | 1010037-00L
6 | 1010025-00L
7 | 1010025-00L
8 | 1010025-00L
9 | 1010025-00L
10 | 1010025-00L
11 | 1010025-00L
12 | 1010025-00L
Something like:
WITH r_nos ( r_no ) AS (
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= ( SELECT MAX( R_to ) FROM your_table )
)
SELECT r_no,
part_no
FROM r_nos r
INNER JOIN
your_table y
ON ( r.r_no BETWEEN y.r_from AND y.r_to )
Here's an alternative which doesn't require a separate join. You should test both solutions to see which is more performant for your data etc, though.
WITH your_table AS (SELECT 1001 order_no, '1010037-00L' part_no, 1 r_from, 5 r_to FROM dual UNION ALL
SELECT 1001 order_no, '1010025-00L' part_no, 6 r_from, 12 r_to FROM dual)
SELECT r_from + LEVEL -1 r_no,
order_no,
part_no
FROM your_table
CONNECT BY PRIOR order_no = order_no
AND PRIOR part_no = part_no
AND PRIOR sys_guid() IS NOT NULL
AND LEVEL <= r_to - r_from + 1
ORDER BY r_no;
R_NO ORDER_NO PART_NO
---------- ---------- -----------
1 1001 1010037-00L
2 1001 1010037-00L
3 1001 1010037-00L
4 1001 1010037-00L
5 1001 1010037-00L
6 1001 1010025-00L
7 1001 1010025-00L
8 1001 1010025-00L
9 1001 1010025-00L
10 1001 1010025-00L
11 1001 1010025-00L
12 1001 1010025-00L

Edit Total line in Oracle report 1

The data structure:
sql-> desc t1
- List item
p_code number,
acc_date date ,
debit number,
credit number
Data inside my table:
sql-> select * from t1;
| p_code | acc_date | debit | credit |
| 001 | 01-01-15 | 100 | 25 |
| 001 | 02-01-15 | 0 | 125 |
| 001 | 03-01-15 | 415 | 85 |
I would like to do something like this:
select * from t1
where acc_date between :fromdate and :todate
union all
select p_code, (sum(nvl(debit,0))- sum(nvl(credit,0))) open_balance
from t1
where acc_date < :fromdate
;
But, I can't figure out what are my mistakes.
Type and number of columns in union must be the same -
select p_code, acc_date, debit, credit, null as open_balance
from t1
where acc_date between :fromdate and :todate
union all
select p_code, null as acc_date, null as debit, null as credit,
(sum(nvl(debit, 0)) - sum(nvl(credit, 0))) open_balance
from t1
where acc_date < :fromdate

Oracle Group by salary range(0-999,1000-1999,2000-2999,...) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
user_id | username | salary |
+---------+----------+------+
| 1 | John | 4000 |
| 2 | Paul | 0900 |
| 3 | Adam | 0589 |
| 4 | Ben | 2154 |
| 5 | Charles | 2489 |
| 6 | Dean | 2500 |
| 7 | Edward | 2900 |
| 8 | Fred | 2800 |
| 9 | George | 4100 |
| 10 | Hugo | 5200 |
I need output like this
range count
--------------------
0-999 2
1000-1999 0
2000-2999 5
3000-3999 0
4000-4999 2
5000-5999 1
Here is an attempt:
with w as
(
select 1000 * (level - 1) low, 1000 * level high from dual
connect by level <= 10
)
select w.low, w.high, sum(decode(t.user_id, null, 0, 1)) nb
from w, test_epn t
where w.low <= t.salary (+)
and w.high > t.salary (+)
group by w.low, w.high
order by w.low
;
This gives:
1 0 1000 2
2 1000 2000 0
3 2000 3000 5
4 3000 4000 0
5 4000 5000 2
6 5000 6000 1
7 6000 7000 0
8 7000 8000 0
9 8000 9000 0
10 9000 10000 0
SQL> col range format a30
SQL> with t as (
2 select 'John' name, 4000 sal from dual union all
3 select 'Paul' name, 900 from dual union all
4 select 'Adam' name, 589 from dual union all
5 select 'Ben' name, 2154 from dual union all
6 select 'Charles' name, 2489 from dual union all
7 select 'Dean' name, 2500 from dual union all
8 select 'Edward' name, 2900 from dual union all
9 select 'Fred' name, 2800 from dual union all
10 select 'George' name, 4100 from dual union all
11 select 'Hugo' name, 5200 from dual
12 )
13 select to_char(pvtid*1000)||'-'||to_char(pvtid*1000+999) range, count(t.sal)
14 from t
15 ,
16 (
17 select rownum-1 pvtid
18 from dual connect by level <= (select floor(max(sal)/1000) from t)+1
19 ) piv
20 where piv.pvtid = floor(t.sal(+)/1000)
21 group by piv.pvtid
22 order by 1
23 /
RANGE COUNT(T.SAL)
------------------------------ ------------
0-999 2
1000-1999 0
2000-2999 5
3000-3999 0
4000-4999 2
5000-5999 1
Oracle 11g R2 Schema Setup:
create table test_table as
select 1 user_id, 'John' username , 4000 salary from dual union all
select 2 , 'Paul' , 0900 from dual union all
select 3 , 'Adam' , 0589 from dual union all
select 4 , 'Ben' , 2154 from dual union all
select 5 , 'Charles' , 2489 from dual union all
select 6 , 'Dean' , 2500 from dual union all
select 7 , 'Edward' , 2900 from dual union all
select 8 , 'Fred' , 2800 from dual union all
select 9 , 'George' , 4100 from dual union all
select 10 , 'Hugo' , 5200 from dual
Query 1:
with range_tab(f,t) as (select (level - 1)*1000 , (level - 1)*1000 + 999
from dual
connect by (level - 1)*1000 <= (select max(salary) from test_table))
select f ||'-'|| t as range, count(user_id)
from test_table
right outer join range_tab on (salary between f and t)
group by f, t
order by 1
[Results][2]:
| RANGE | COUNT(USER_ID) |
|-----------|----------------|
| 0-999 | 2 |
| 1000-1999 | 0 |
| 2000-2999 | 5 |
| 3000-3999 | 0 |
| 4000-4999 | 2 |
| 5000-5999 | 1 |
In case of fixed interval you can also use Oracle WIDTH_BUCKET function.
select count(*),
(WIDTH_BUCKET(salary, 0, 10000,10)-1)*1000 ||'-'||to_char(WIDTH_BUCKET(salary, 0, 10000,10)*1000-1) as salary_range
from table1
group by WIDTH_BUCKET(salary, 0, 10000,10)
order by salary_range;
| COUNT(*) | SALARY_RANGE |
|----------|--------------|
| 2 | 0-999 |
| 5 | 2000-2999 |
| 2 | 4000-4999 |
| 1 | 5000-5999 |
Disadvantage is: It does not count empty buckets, but maybe this satisfy your needs anyway.

Resources