Oracle - generate a running number by group - sql

I need to generate a running number / group sequence inside a select statement for a group of data.
For example
Group Name Sequence
1 a 1
1 b 2
1 c 3
2 d 1
2 e 2
2 f 3
So for each group the sequence should be a running number starting with 1 depending on the order of column"Name".
I already pleayed around with Row_Number() and Level but I couldn't get a solution.
Any idea how to do it?

Analytic functions help.
SQL> with test (cgroup, name) as
2 (select 1, 'a' from dual union all
3 select 1, 'b' from dual union all
4 select 1, 'c' from dual union all
5 select 2, 'd' from dual union all
6 select 2, 'e' from dual union all
7 select 2, 'f' from dual
8 )
9 select cgroup,
10 name,
11 row_number() over (partition by cgroup order by name) sequence
12 from test
13 order by cgroup, name;
CGROUP N SEQUENCE
---------- - ----------
1 a 1
1 b 2
1 c 3
2 d 1
2 e 2
2 f 3
6 rows selected.
SQL>

Try this
SELECT
"Group",
Name,
DENSE_RANK() OVER (PARTITION BY "Group" ORDER BY Name) AS Sequence
FROM table;

Related

Query to delete duplicate records by keeping original in oracle

This is the table.
Id. Name
1 A
1 A
2 B
2 C
1 A
2 B
2 D
The output should be
Id. Name
1 A
2 B
2 C
2 D
please try
Select distinct id, name
from <name of you table>
order by name
Check this link.
Sample data:
create table demo (id, name) as
select 1, 'A' from dual union all
select 1, 'A' from dual union all
select 2, 'B' from dual union all
select 2, 'C' from dual union all
select 1, 'A' from dual union all
select 2, 'B' from dual union all
select 2, 'D' from dual;
select * from demo order by 1,2;
ID NAME
---------- ------------------------------
1 A
1 A
1 A
2 B
2 B
2 C
2 D
7 rows selected
Delete all but the first row in each (id, name) group:
delete demo where rowid in
( select lag(rowid) over (partition by id, name order by null) from demo );
3 rows deleted
select * from demo order by 1,2
ID N
---------- -
1 A
2 B
2 C
2 D
4 rows selected.

Always show a value highst when sorting

I Oracle, I have a table with following values
1
2
4
10
I always want 2 to show up highest following by all other values in DESCending order, as follows :
2
10
4
1
You can order by a value you build with a case; for example:
with tab(col) as (
select 1 from dual union all
select 2 from dual union all
select 4 from dual union all
select 10 from dual
)
select col
from tab
order by case when col = 2 then 1 else 2 end asc,
col desc
gives:
COL
----------
2
10
4
1
try like below if column is not null
with tab(col) as (
select 1 from dual union all
select 2 from dual union all
select 4 from dual union all
select 10 from dual
)
select col
from tab
ORDER BY NULLIF(col, 2) desc NULLS FIRST
output
COL
2
10
4
1
demo link

Oracle get difference in Average of Current and Previous group (partition)

I am using Oracle 12.1.0.2.0
I want difference in average of current group(partition) - average of previous group(partition)
My code to get current group Average is
with rws as (
select rownum x, mod(rownum, 2) y from dual connect by level <= 10
), avgs as (
select x, y, avg(x) over (partition by y) mean from rws
)
select x, y, mean
from avgs;
Now I want something like :
X Y MEAN PREV_MEAN MEAN_DIFF
4 0 6
8 0 6
2 0 6
6 0 6
10 0 6
9 1 5 6 -1
7 1 5
3 1 5
1 1 5
5 1 5
2 2 3 5 -3
3 2 3
5 2 3
1 2 3
4 2 3
AVG( this partitioned group) - Avg( previous partition group)
In this case I need ( 5 - 6 ) to compute in GROUP_MEAN_DIFFERENCE column.
Also How can I get mean difference always w.r.t first group.
In the example above I need (5 - 6) and (3 - 6)
Can you please assist?
Use the function lag() with ignore nulls clause:
select id, val, av, av - lag(av ignore nulls) over (order by id) diff
from (select id, val,
case when row_number() over (partition by id order by null) = 1
then avg(val) over (partition by id) end av
from t)
order by id
Test:
with t (id, val) as (select 1, 44.520 from dual union all
select 1, 47.760 from dual union all
select 1, 50.107 from dual union all
select 1, 48.353 from dual union all
select 1, 47.640 from dual union all
select 2, 48.353 from dual union all
select 2, 50.447 from dual union all
select 2, 51.967 from dual union all
select 2, 45.800 from dual union all
select 2, 46.913 from dual )
select id, val, av, av - lag(av ignore nulls) over (order by id) diff
from (select id, val,
case when row_number() over (partition by id order by null) = 1
then avg(val) over (partition by id) end av
from t)
order by id
Output:
ID VAL AV DIFF
--- ------- ------- -------
1 44.520 47.676
1 47.760
1 50.107
1 48.353
1 47.640
2 48.353 48.696 1.02
2 50.447
2 51.967
2 45.800
2 46.913

How to combine and count two columns in oracle?

My table seems like this;
A B
1 100
1 102
1 105
2 100
2 105
3 100
3 102
I want output like this:
A Count(B)
1 3
1,2 2
1,2,3 3
2 2
3 2
2,3 2
How can i do this?
I try to use listagg but it didn't work.
I suspect that you want to count the number of sets of A that are in the data -- and that your sample results are messed up.
If so:
select grp, count(*)
from (select listagg(a, ',') within group (order by a) as grp
from t
group by b
) b;
This gives you the counts for the full combinations present in the data. The results would be:
1,2,3 1
1,3 1
1,2 1
You can get the original number of rows by doing:
select grp, sum(cnt)
from (select listagg(a, ',') within group (order by a) as grp, count(*) as cnt
from t
group by b
) b;
Oracle Setup:
CREATE TABLE table_name ( A, B ) AS
SELECT 1, 100 FROM DUAL UNION ALL
SELECT 1, 102 FROM DUAL UNION ALL
SELECT 1, 105 FROM DUAL UNION ALL
SELECT 2, 100 FROM DUAL UNION ALL
SELECT 2, 105 FROM DUAL UNION ALL
SELECT 3, 100 FROM DUAL UNION ALL
SELECT 3, 102 FROM DUAL;
Query:
SELECT A,
COUNT(B)
FROM (
SELECT SUBSTR( SYS_CONNECT_BY_PATH( A, ',' ), 2 ) AS A,
B
FROM table_name
CONNECT BY PRIOR B = B
AND PRIOR A + 1 = A
)
GROUP BY A
ORDER BY A;
Output:
A COUNT(B)
----- ----------
1 3
1,2 2
1,2,3 1
2 2
2,3 1
3 2

Oracle logic to roll the value same level

I am facing issue is solving on oracle logic
I have below requirement, I have one table with Some Numbers and Corresponding ID. I want to write logic where few rows are rolled same No. Please let me know what is best way to solve this. I have used left outer join on same table but its giving me cross join.
NO ID
1 A
1 B
1 C
2 A
2 B
2 C
NO ID RoID
1 A C
1 B
2 A C
2 B
You could achieve your desired output using Analytic functions:
MAX() OVER()
LAG() OVER()
For example,
SQL> WITH sample_data AS(
2 SELECT 1 NO, 'A' ID FROM dual UNION ALL
3 SELECT 1 NO, 'B' ID FROM dual UNION ALL
4 SELECT 1 NO, 'C' ID FROM dual UNION ALL
5 SELECT 2 NO, 'A' ID FROM dual UNION ALL
6 SELECT 2 NO, 'B' ID FROM dual UNION ALL
7 SELECT 2 NO, 'C' ID FROM dual
8 )
9 -- end of sample_data mocking a real table
10 SELECT no,
11 id,
12 lag(rn) over(PARTITION BY NO ORDER BY ID DESC) rn
13 FROM
14 ( SELECT t.*, MAX(ID) OVER(PARTITION BY NO ORDER BY ID DESC) rn FROM sample_data t
15 )
16 WHERE ID <> rn
17 ORDER BY no,
18 id;
NO I R
---------- - -
1 A C
1 B
2 A C
2 B