Want to convert rows to columns - oracle

I have one table t as below
Customer _no | receipt_no
----------------------------
A | 123
A. | 234
A. | 345
B. | 465
B. | 675
I want result as
Customer _no | receipt_1 | receipt_2
A. | 123. | 234
A. | 345. | Null
B. | 465. | 675
Please suggest how to do this

If I understood it correctly, you want to have two columns for each customer. If that's so, here's one option.
SQL> with test (cno, rno) as
2 (select 'A', 123 from dual union all
3 select 'A', 234 from dual union all
4 select 'A', 345 from dual union all
5 select 'A', 444 from dual union all
6 select 'A', 555 from dual union all
7 select 'B', 456 from dual union all
8 select 'B', 675 from dual
9 ),
10 inter as
11 (select cno, rno,
12 row_number() over (partition by cno order by cno, rno) rn,
13 round(row_number() over (partition by cno order by cno, rno) /2) grp
14 from test
15 )
16 select cno,
17 max(decode(mod(rn, 2), 1, rno)) r1,
18 max(decode(mod(rn, 2), 0, rno)) r2
19 from inter
20 group by cno, grp
21 order by cno, grp;
C R1 R2
- ---------- ----------
A 123 234
A 345 444
A 555
B 456 675
SQL>

Related

oracle ROW_NUMBER()

I would like to write a query to display this kind of results
column0
column1
column2
column3
a
x
1
1
a
y
1
2
a
z
1
3
b
x
2
1
b
y
2
2
c
x
3
1
c
y
3
2
c
z
3
3
column2 -> row number of column0
column3 -> row number of partition column0 & column1
I have tried this but not working
SELECT ROW_NUMBER() OVER (PARTITION BY column0 ORDER BY column0 ) column2,
ROW_NUMBER() OVER (PARTITION BY column0 , column1 ORDER BY column0 , column1) column3
FROM DUAL
have you got any ideas ?
Use DENSE_RANK for column2 and ROW_NUMBER for column3:
SELECT
column0,
column1,
DENSE_RANK() OVER (ORDER BY column0) AS column3,
ROW_NUMBER() OVER (PARTITION BY column0 ORDER BY column1) AS column4
FROM yourTable;
With row_number:
SQL> with test (col0, col1) as
2 (select 'a', 'x' from dual union all
3 select 'a', 'y' from dual union all
4 select 'a', 'z' from dual union all
5 select 'b', 'x' from dual union all
6 select 'b', 'y' from dual
7 )
8 select col0, col1,
9 row_number() over (partition by col1 order by col0) col2,
10 row_number() over (partition by col0 order by col1) col3
11 from test
12 order by col0, col1
13 /
COL0 COL1 COL2 COL3
----- ------ ---------- ----------
a x 1 1
a y 1 2
a z 1 3
b x 2 1
b y 2 2
SQL>

how to get if value not in oracle group by

I have a table named statustimeline which has structure as
id | applicationid | status | createdon
---+---------------+--------+----------
11 |1 |4 |
---+---------------+--------+----------
10 |1 |3 |
---+---------------+--------+----------
9 |1 |2 |
---+---------------+--------+----------
8 |1 |1 |
---+---------------+--------+----------
7 |2 |3 |
---+---------------+--------+----------
6 |2 |2 |
---+---------------+--------+----------
5 |2 |1 |
---+---------------+--------+----------
4 |3 |5 |
---+---------------+--------+----------
3 |3 |3 |
---+---------------+--------+----------
2 |3 |2 |
---+---------------+--------+----------
1 |3 |1 |
---+---------------+--------+----------
if I partition it on application id, there will be three groups.
select applicationid,ngstatus, row_number() over (partition by applicationid order by id desc) rownumbr
from applicationstatustimeline ;
i want to select only those applicationid whose group never had status=4 (applicationid = 2 and applicationid = 3 in this case)
is there any function?
Why not a simple minus set operator?
SQL> with statustimeline (id, applicationid, status) as
2 -- sample data
3 (select 11, 1, 4 from dual union all
4 select 10, 1, 3 from dual union all
5 select 9, 1, 2 from dual union all
6 select 8, 1, 1 from dual union all
7 select 7, 2, 3 from dual union all
8 select 6, 2, 2 from dual union all
9 select 5, 2, 1 from dual union all
10 select 4, 3, 5 from dual union all
11 select 3, 3, 3 from dual union all
12 select 2, 3, 2 from dual union all
13 select 1, 3, 1 from dual
14 )
15 -- query you need
16 select applicationid
17 from statustimeline
18 minus
19 select applicationid
20 from statustimeline
21 where status = 4;
APPLICATIONID
-------------
2
3
SQL>
If you want to use analytic functions here, we can use COUNT:
WITH cte AS (
SELECT t.*,
COUNT(CASE WHEN status = 4 THEN 1 END) OVER (PARTITION BY applicationid) AS four_cnt
FROM applicationstatustimeline t
)
SELECT id, applicationid, status, createdon
FROM cte
WHERE four_cnt = 0;
In the CTE above, we generate a computed column four_cnt, whose value would be identical for every group of applicationid records. That value would be zero assuming status=4 never occurs, otherwise it would be some value greater than zero.
Yet other option is to use the NOT EXISTS as follows:
SELECT *
FROM STATUSTIMELINE S
WHERE S.STATUS <> 4
AND NOT EXISTS (
SELECT 1
FROM STATUSTIMELINE S4
WHERE S4.STATUS = 4
AND S.APPLICATIONID = S4.APPLICATIONID
);
Yet another option is to use the NOT IN as follows:
SELECT *
FROM STATUSTIMELINE S
WHERE S.STATUS <> 4
AND S.APPLICATIONID NOT IN (
SELECT S4.APPLICATIONID
FROM STATUSTIMELINE S4
WHERE S4.STATUS = 4
)

Oracle: How to restart row_number function

I have a scenario where in I need to assign row_number for a data grouped by department, branch, amount and ordering by date.
If the amount repeats after some dates for the same department & branch, I would like to have the row_number as 1.
Could you please let me know how to achieve this?
When I tried with Row_number function the numbering is continuing after some dates.
Sample Data:
This is the row numbers I am getting if the following function is used row_number() over(Partition by Department, Branch, Amount order by Date)
Department Branch Amount Date Row_number()
Dep A Bran 1 51 25-Oct-12 1
Dep A Bran 1 45.5 26-Nov-12 1
Dep A Bran 1 45.5 05-Apr-13 2
Dep A Bran 1 45.5 06-May-13 3
Dep A Bran 1 65 07-May-13 1
Dep A Bran 1 51 26-Aug-13 2
Dep A Bran 1 51 11-Sep-13 3
But I am expecting output in the below order.
Department Branch Amount Date Row_number()
Dep A Bran 1 51 25-Oct-12 1
Dep A Bran 1 45.5 26-Nov-12 1
Dep A Bran 1 45.5 05-Apr-13 2
Dep A Bran 1 45.5 06-May-13 3
Dep A Bran 1 65 07-May-13 1
Dep A Bran 1 51 26-Aug-13 1
Dep A Bran 1 51 11-Sep-13 2
Could anyone help me on this?
You need to change how you identify the groups inside which you calculate row_number().
Something like:
SQL> with t (Department, Branch, Amount, Date#)
2 as (
3 select 'Dep A', 'Bran 1', 51, to_date('25-10-2012','DD-MM-YYYY') from dual union all
4 select 'Dep A', 'Bran 1', 45.5, to_date('26-11-2012','DD-MM-YYYY') from dual union all
5 select 'Dep A', 'Bran 1', 45.5, to_date('05-04-2013','DD-MM-YYYY') from dual union all
6 select 'Dep A', 'Bran 1', 45.5, to_date('06-05-2013','DD-MM-YYYY') from dual union all
7 select 'Dep A', 'Bran 1', 65, to_date('07-05-2013','DD-MM-YYYY') from dual union all
8 select 'Dep A', 'Bran 1', 51, to_date('26-08-2013','DD-MM-YYYY') from dual union all
9 select 'Dep A', 'Bran 1', 51, to_date('11-09-2013','DD-MM-YYYY') from dual
10 )
11 select department, branch, amount, date#, row_number() over(partition by grp order by date#) rn
12 from (
13 select department, branch, amount, date#, sum(st_grp) over(order by date#) grp from (
14 select department, branch, amount, date#, case when amount = lag(amount,1,amount) over(order by date#) then 0 else 1 end st_grp from t
15 )
16 )
17 order by date#
18 /
DEPAR BRANCH AMOUNT DATE# RN
----- ------ ---------- -------- ----------
Dep A Bran 1 51 25.10.12 1
Dep A Bran 1 45,5 26.11.12 1
Dep A Bran 1 45,5 05.04.13 2
Dep A Bran 1 45,5 06.05.13 3
Dep A Bran 1 65 07.05.13 1
Dep A Bran 1 51 26.08.13 1
Dep A Bran 1 51 11.09.13 2

Ranking with Duplicates

I am using Oracle Apex and I am ranking call speed. I am almost getting the results I am after. The only issue that I have faced is that when the rank function comes across duplicate values, by default they both get assigned the lowest Rank. e.g.
Rank Call Speed
1 65
2 72
3 92
4 102
4 102
4 102
4 102
4 102
9 113
10 154
11 201
12 352
Is there anyway to have the 4's represent as 8's (the highest rank of the duplicates)
One way of doing this is by using the ranking Descending and then subtracting this from the highest rank + 1. this works but seems like an unnecessary step.
Any help will be much appreciated
Kind of a strange thing to do, but I would do something like:
with data as (
select 65 call_speed from dual union all
select 72 call_speed from dual union all
select 92 call_speed from dual union all
select 102 call_speed from dual connect by level <= 5 union all
select 113 call_speed from dual union all
select 154 call_speed from dual union all
select 201 call_speed from dual union all
select 352 call_speed from dual
)
select
rank() over (order by call_speed) + count(*) over (partition by call_speed) - 1 rank,
call_speed
from data;
Which gives you:
RANK CALL_SPEED
---------- ----------
1 65
2 72
3 92
8 102
8 102
8 102
8 102
8 102
9 113
10 154
11 201
12 352
Just an alternative, for no reason at all, except maybe to avoid any memory overhead (?) from doing a partitioned count:
with data as (
select 65 call_speed from dual union all
select 72 call_speed from dual union all
select 92 call_speed from dual union all
select 102 call_speed from dual connect by level <= 5 union all
select 113 call_speed from dual union all
select 154 call_speed from dual union all
select 201 call_speed from dual union all
select 352 call_speed from dual
)
select
count(*) over () + 1 - rank() over (order by call_speed desc) rank,
call_speed
from data
order by call_speed;

How to sort individual rows in descending order?

I have a table which looks like the following:
Name LastName tPoints aPoints sPoints gPoints type
John Johnny 15 14 13 10 1
Joe P. 12 11 26 10 1
Matt Q. 11 26 37 44 2
Sorine P. 55 9 8 7 2
Ali Ahmed 30 44 88 65 2
... ... .. .. .. .. 3
3
I would like to sort INDIVIDUAL ROWS and display based on TYPE
NOTE: i can't use order by in oracle because it sorts only 1 row and the others
is sorted based on the first row
I don't want to break the table apart into individual tables, then sort it, and then update it back to the original table.
so, the output will looks something like this, for tPoints - i need to display all
15 - John Johnny
12 - Joe P.
and for aPoints
44 - Ali Ahmed
26 - Matt Q.
9 - Sorine P.
and so on ...
in a nutshell, if type = 1 then sort tPoints in descending, if type = 2 then sort aPoints, if type = 3 then sort sPoints, and so on....
what would be an efficient way to chive this?
Regards,
For the sake of simplicity this example includes only two types. Add as many types as you need.
SQL> with t1(Name1, LastName, tPoints, aPoints, sPoints, gPoints, type1) as(
2 select 'John' , 'Johnny', 15, 14, 13, 10, 1 from dual union all
3 select 'Joe' , 'P.' , 12, 11, 26, 10, 1 from dual union all
4 select 'Matt' , 'Q.' , 11, 26, 37, 44, 2 from dual union all
5 select 'Sorine', 'P.' , 55, 9 , 8 , 7, 2 from dual union all
6 select 'Ali' , 'Ahmed' , 30, 44, 88, 65, 2 from dual
7 )
8 select type1
9 , tpoints
10 , apoints
11 , name1
12 , Lastname
13 from t1
14 order by case when type1=1 then tpoints else type1 end desc,
15 case when type1=2 then apoints else type1 end desc;
TYPE1 TPOINTS APOINTS NAME1 LASTNAME
---------- ---------- ---------- ------ --------
1 15 14 John Johnny
1 12 11 Joe P.
2 30 44 Ali Ahmed
2 11 26 Matt Q.
2 55 9 Sorine P.

Resources