Reset Row Number in Oracle conditionally - sql

I have this record set returned , now I want to have a row number column which gets reset after every 3rd row. Can anyone help me with this? needs to be done with Oracle SQL.
Explanation below-
data
current row number
rquired row number
Chris
1
1
Bryan
2
2
Jim
3
3
Davis
4
1
Kia
5
2
Jones
6
3
Mary
7
1
Carrie
8
2
Pearce
9
3
Cesar
10
1
Bob
11
2

You can mod the current value:
mod(current_row_num - 1, 3) + 1
So using a CTE to represent your current result set:
with your_result (data, current_row_num) as (
select 'Chris', 1 from dual union all
select 'Bryan', 2 from dual union all
select 'Jim', 3 from dual union all
select 'Davis', 4 from dual union all
select 'Kia', 5 from dual union all
select 'Jones', 6 from dual union all
select 'Mary', 7 from dual union all
select 'Carrie', 8 from dual union all
select 'Pearce', 9 from dual union all
select 'Cesar', 10 from dual union all
select 'Bob', 11 from dual
)
select data, current_row_num, mod(current_row_num - 1, 3) + 1 as required_row_num
from your_result
order by current_row_num
DATA
CURRENT_ROW_NUM
REQUIRED_ROW_NUM
Chris
1
1
Bryan
2
2
Jim
3
3
Davis
4
1
Kia
5
2
Jones
6
3
Mary
7
1
Carrie
8
2
Pearce
9
3
Cesar
10
1
Bob
11
2
db<>fiddle

Related

Identifying the transitive match records in oracle SQL

SOURCE
Rowid_object
Rowid_object_matched
1
2
1
3
3
2
2
4
4
6
6
5
7
8
9
8
Target
Rowid_object
Rowid_object_matched
1
1
2
1
3
1
4
1
5
1
6
1
7
7
8
7
9
7
Here, we have Source like data and we want Target like result.
There are two groups in source which are in transitive match.
Need to identify these kind of record.
In Oracle, you can use:
SELECT rowid_object,
MIN(root) AS rowid_object_matched
FROM (
SELECT CONNECT_BY_ROOT(rowid_object) AS root,
rowid_object,
rowid_object_matched
FROM source
CONNECT BY NOCYCLE
PRIOR rowid_object IN (rowid_object, rowid_object_matched)
OR PRIOR rowid_object_matched IN (rowid_object, rowid_object_matched)
)
UNPIVOT (
rowid_object FOR key IN (rowid_object, rowid_object_matched)
)
GROUP BY rowid_object;
Which, for the sample data:
CREATE TABLE SOURCE (Rowid_object, Rowid_object_matched) AS
SELECT 1, 2 FROM DUAL UNION ALL
SELECT 1, 3 FROM DUAL UNION ALL
SELECT 3, 2 FROM DUAL UNION ALL
SELECT 2, 4 FROM DUAL UNION ALL
SELECT 4, 6 FROM DUAL UNION ALL
SELECT 6, 5 FROM DUAL UNION ALL
SELECT 7, 8 FROM DUAL UNION ALL
SELECT 9, 8 FROM DUAL;
Outputs:
ROWID_OBJECT
ROWID_OBJECT_MATCHED
1
1
2
1
3
1
4
1
6
1
5
1
7
7
8
7
9
7
fiddle

List number into TABLE records by the value in another table

Sorry for a little bit confuse on the title.
I would like to use SQL for join sequence table as below
Original Table Records
3
3
4
1
Result Table
1
2
3
1
2
3
1
2
3
4
1
Based on comment you posted,
sample data:
SQL> with test (col) as
2 (select 3 from dual union all
3 select 3 from dual union all
4 select 4 from dual union all
5 select 1 from dual
6 )
Query begins here:
7 select column_value
8 from test cross join
9 table(cast(multiset(select level from dual
10 connect by level <= col
11 ) as sys.odcinumberlist));
COLUMN_VALUE
------------
1
2
3
1
2
3
1
2
3
4
1
11 rows selected.
SQL>

how to convert distinct row values into column [duplicate]

This question already has answers here:
Dynamic Pivot in Oracle's SQL
(10 answers)
Closed last year.
Here is my data
Id type count
1 jim 2
1 bim 2
1 sim 3
1 pim 1
2 jim 2
2 bim 1
Want to convert this data into below
Id jim bim sim pim
1 2 2 3 1
2 2 1 0 0
Tried this, its now working
select * FROM table
PIVOT
(
Min(Id)
FOR Id IN (select distinct(type) from table)
)
I'm trying to convert all distinct values of type row into columns and then assign respective values against every ID. Any suggestion please ?
Error
ORA-00936: missing expression
00936. 00000 - "missing expression"
*Cause:
*Action:
Error at Line: 26 Column: 16
Would this do?
SQL> with test (id, type, count) as
2 (select 1, 'jim', 2 from dual union all
3 select 1, 'bim', 2 from dual union all
4 select 1, 'sim', 3 from dual union all
5 select 1, 'pim', 1 from dual union all
6 select 2, 'jim', 2 from dual union all
7 select 2, 'bim', 1 from dual
8 )
9 select id, nvl(jim, 0) jim,
10 nvl(bim, 0) bim,
11 nvl(sim, 0) sim,
12 nvl(pim, 0) pim
13 from test
14 pivot
15 (min(count)
16 for type in ('jim' as jim, 'bim' as bim, 'sim' as sim, 'pim' as pim)
17 );
ID JIM BIM SIM PIM
---------- ---------- ---------- ---------- ----------
1 2 2 3 1
2 2 1 0 0
SQL>

Oracle - How to count average of attendance on based on concert itself?

How to count an average of attendance based on concert_id?
So far what i have done is like this
select concert_id, event_id, count(customer_id) attendance,
case when concert_id = 1
then (select count(customer_id)/count(concert_id)
from booking where concert_id=1)
end as avg_attendance_each_concert
from booking
group by event_id, concert_id
order by event_id;
result
CONCERT_ID EVENT_ID ATTENDANCE AVG_ATTENDANCE_EACH_CONCERT
---------- ---------- ---------- ---------------------------
1 1 1 3
1 2 2 3
2 3 2
2 4 1
3 5 2
3 6 2
4 8 2
4 9 2
5 11 4
5 12 1
5 13 1
How to make AVG_ATTENDANCE_EACH_CONCERT become like this?
CONCERT_ID EVENT_ID ATTENDANCE AVG_ATTENDANCE_EACH_CONCERT
---------- ---------- ---------- ---------------------------
1 1 1 1.5 --> 3 attendance / 2 same concert_id
1 2 2 1.5
2 3 2 1.5 --> 3 attendance / 2 same concert_id
2 4 1 1.5
3 5 2 2 --> 4 attendance / 2 same concert_id
3 6 2 2
4 8 2 2 --> 4 attendance / 2 same concert_id
4 9 2 2
5 11 4 2 --> 6 attendance / 3 same concert_id
5 12 1 2
5 13 1 2
Because I would like to show which event have below average attendance
How about AVG in its analytic form?
(By the way, your example for CONCERT_ID = 5 is wrong; 6 / 3 = 2, not 3).
SQL> with booking (concert_id, event_id, customer_id) as
2 (select 1, 1, 10 from dual union
3 select 1, 2, 10 from dual union
4 select 1, 2, 20 from dual union
5 --
6 select 3, 5, 10 from dual union
7 select 3, 5, 20 from dual union
8 select 3, 6, 30 from dual union
9 select 3, 6, 40 from dual union
10 --
11 select 5, 11, 10 from dual union
12 select 5, 11, 20 from dual union
13 select 5, 11, 30 from dual union
14 select 5, 11, 40 from dual union
15 select 5, 12, 50 from dual union
16 select 5, 13, 60 from dual
17 )
18 select concert_id, event_id, count(customer_id) attendance,
19 avg(count(*)) over (partition by concert_id) avg_attendance_each_concert
20 from booking
21 group by concert_id, event_id
22 order by event_id;
CONCERT_ID EVENT_ID ATTENDANCE AVG_ATTENDANCE_EACH_CONCERT
---------- ---------- ---------- ---------------------------
1 1 1 1,5
1 2 2 1,5
3 5 2 2
3 6 2 2
5 11 4 2
5 12 1 2
5 13 1 2
7 rows selected.
SQL>

Split words and insert it new table with counting these words

I have the foolwoing table and data.
i need to:
1- split each sentence in each row into new row
2-count the words in each row based on last part of sentence based on soundex function
create table a (id number(9), words varchar(500));
insert into a values(1,'UK,LONDON,YEMEN,JOHN,CAIRO,OMAR ALI,EGYPT,Cairo,YEMAN,OMAR AMR ALI,LONDAN');
insert into a values(2,'UK,SUDAI,SUDAIN,AYHAM SHAHER YAFOOZ,ALI YAFOOZ');
insert into a values(3,'MALAYSIA, AHMED ALI,MALYSIAN');
expexted output
create table temp_words(id number(9),words varchar2(100), count_words number(9));
id words count_words
1 UK 1
1 LONDON 2
1 YEMEN 2
1 CAIRO 2
1 OMAR ALI 2
1 JOHN 1
2 UK 1
2 SUDAI 2
2 AYHAM SHAHER YAFOOZ 2
3 MALAYSIA 2
3 AHMED ALI 1
regards
to split the data as you want you can use a "connect by" as a row generator.
SQL> with src as (select id,',' || words || ',' as words,
2 length(words) - length(translate(words, '.,', '.')) + 1 no_of_words
3 from a)
4 select a.id,
5 substr(a.words,
6 instr(words, ',', 1, r) + 1,
7 instr(words, ',', 1, r + 1) - instr(words, ',', 1, r) - 1) word,
8 a.no_of_words
9 from (select level r
10 from dual
11 connect by level <= (select max(no_of_words) from src)) d
12 inner join src a
13 on d.r <= a.no_of_words
14 where a.no_of_words is not null
15 order by a.id, d.r
16 /
ID WORD NO_OF_WORDS
---------- -------------------- -----------
1 UK 11
1 LONDON 11
1 YEMEN 11
1 JOHN 11
1 CAIRO 11
1 OMAR ALI 11
1 EGYPT 11
1 Cairo 11
1 YEMAN 11
1 OMAR AMR ALI 11
1 LONDAN 11
2 UK 5
2 SUDAI 5
2 SUDAIN 5
2 AYHAM SHAHER YAFOOZ 5
2 ALI YAFOOZ 5
3 MALAYSIA 3
3 AHMED ALI 3
3 MALYSIAN 3
19 rows selected.
SQL>
Here is a SQLFiddle demo
select id,words,
case when i=0 then
SUBSTR(words,
1,
case when INSTR(words,',', 1, 1)=0
then 100000
else
INSTR(words,',', 1, 1)-1
end
)
ELSE
SUBSTR(words,
INSTR(words,',', 1, i)+1,
case when INSTR(words,',', 1, i+1)=0
then 100000
else
INSTR(words,',', 1, i+1)-INSTR(words,',', 1, i)-1
end
)
END word,
i+1 COUNTWORDS
from a,
(
select * from
(
select 0 i from dual
union
select 1 i from dual
union
select 2 i from dual
union
select 3 i from dual
union
select 4 i from dual
union
select 5 i from dual
union
select 6 i from dual
union
select 7 i from dual
union
select 8 i from dual
union
select 9 i from dual
union
select 10 i from dual
union
select 11 i from dual
union
select 12 i from dual
)
)
table_i
where
case when i>0 then INSTR(words,',', 1, i)
else 100000 end <>0
order by id,i
Another approach(using regexp_count and regexp_substr regular expression functions):
SQL> with Occurence(oc) as(
2 select level
3 from ( select max(regexp_count(words, '[^,]+')) ml
4 from a
5 ) t
6 connect by level <= t.ml
7 )
8 select id
9 , word
10 , count(word) over(partition by id, soundex(word) order by id) as count_words
11 From ( select a.id
12 , regexp_substr(words, '[^,]+', 1, o.oc) as word
13 from occurence o
14 cross join a
15 ) s
16 where s.word is not null
17 order by id
18 ;
ID WORD COUNT_WORDS
---------- -------------------- -----------
1 Cairo 2
1 CAIRO 2
1 EGYPT 1
1 JOHN 1
1 LONDAN 2
1 LONDON 2
1 OMAR ALI 1
1 OMAR AMR ALI 1
1 UK 1
1 YEMEN 2
1 YEMAN 2
2 ALI YAFOOZ 1
2 AYHAM SHAHER YAFOOZ 1
2 SUDAI 1
2 SUDAIN 1
2 UK 1
3 AHMED ALI 1
3 MALAYSIA 1
3 MALYSIAN 1
19 rows selected
You would need to insert your data as separate records. You can keep them as a concatenated string, if you like, but it'll just make your life very difficult. So:
create table words (
id number,
w varchar2(100),
s varchar2(4)
);
create or replace trigger words_auto
before insert or update on words
for each row
begin
select trim(upper(:new.w)), soundex(:new.w)
into :new.w, :new.s
from dual;
end;
insert into words (id, w) values (1, 'UK');
insert into words (id, w) values (1, 'LONDON');
...
insert into words (id, w) values (3, ' AHMED ALI');
insert into words (id, w) values (3, 'MALYSIAN');
You could write a procedure to split your concatenated string and populate the words table appropriately. Note that I have created a trigger that normalises your input to uppercase, removing all extraneous whitespace and automatically produces the Soundex codes.
Now here's a question: You want to group words by their Soundex codes; however, how do you determine the baseline? For example, 'LONDON' and 'LONDAN' both have code 'L535', but how do you know which record is the 'main' one?... You can't, without further lookup tables! As such, the best you can do is to group by the Soundex codes. This doesn't have to be stored in a table and it makes more sense to be a view:
create or replace view word_counts as
select id,
s soundex,
count(w) count_rows
from words
group by id,
s;
Note that I've called the count field count_rows as it counts records, rather than distinct rows. That is: records of 'LONDON', 'LONDAN' and 'LONDON' will show with a count of 3, not 2 (which you might be expecting). Anyway, with your data, the view will look something like this:
id soundex count_rows
----- --------- -----------
1 U200 1
1 L535 2
... ... ...
3 M420 2
3 A534 1
As I say, that's really the best you can expect without further infrastructure.