Oracle Partitioned Sequence

Oracle 12 - Reset a sequence Column with row_number() over Partition

Use a MERGE statement and correlate on the ROWID pseudo-column to efficiently self-join:

MERGE INTO table_name dst
USING (
SELECT ROWID AS rid,
ROW_NUMBER() OVER (
PARTITION BY product
ORDER BY ROWNUM -- or ORDER BY seq
) AS newSeq
FROM table_name
) src
ON ( dst.ROWID = src.rid )
WHEN MATCHED THEN
UPDATE SET seq = src.newSeq;

(Note: You do NOT need an ORDER BY expression appended to the SELECT statement as it will have no practical effect as the order of the source query is irrelevant during the MERGE and could make the SELECT statement less efficient if the ordering is applied and the SQL engine does unnecessary work.)

Which, for the sample data:

CREATE TABLE table_name ( product, "GROUP", seq ) AS
SELECT 10, 5, 1 FROM DUAL UNION ALL
SELECT 10, 1, 5 FROM DUAL UNION ALL
SELECT 11, 2, 3 FROM DUAL UNION ALL
SELECT 11, 4, 4 FROM DUAL UNION ALL
SELECT 11, 24, 5 FROM DUAL

Then results in:

SELECT * FROM table_name




































PRODUCTGROUPSEQ
1051
1012
1121
1142
11243

SQL Partition By Date and Sequence

I think that what you're missing is that the date column includes a time component, and you need to remove that before using it in the PARTITION BY.

WITH
sorted AS
(
SELECT
row_number() OVER (
PARTITION BY item, location, seqn, TRUNC(date)
ORDER BY date
)
AS row_num,
date,
item,
location,
seqn
FROM
table1
)
SELECT
*
FROM
sorted
WHERE
row_num = 1
AND item = 'A1234'
AND location = 'L1'
ORDER BY
location,
item,
seqn,
date

Oracle SQL: Further sort PARTITION BY groups based on first row in each partition

Luckily, you only need to add an analytic max() to the order by clause. You don't need to do anything else.

Suppose "current query" is your existing query, not ordered yet in any way (no order by clause). Add the following at the very end:

... existing query ...
order by max(timetocomplete) over (partition by itemkey) desc,
itemkey,
timetocomplete desc
;

Note that you do not need to add the analytic function to the select clause. The SQL standard says you do; Oracle syntax says you don't. Oracle is taking care of the small additional steps for us, behind the scenes.

This computes the max time to complete for each key. It orders by that max first. In the case of ties (two or more different keys with the same max time to complete), it further orders by key first, and then within each key, by time to complete (descending).

Oracle SQL or PLSQL. Select rows by partitions which values have specific order

You can do it by only reading the table once using the Tabibitosan method to group sequential competitions together https://www.red-gate.com/simple-talk/sql/t-sql-programming/the-sql-of-gaps-and-islands-in-sequences/#:%7E:text=The%20SQL%20of%20Gaps%20and%20Islands%20in%20Sequences,...%204%20Performance%20Comparison%20of%20Gaps%20Solutions.%20

Here you would have to use add_months because your competitions are months apart:

select sportsman_id, min(hold_date) , max(hold_date), comps_in_island
from (
select competition_id, sportsman_id, hold_date, island, count(*) over (partition by sportsman_id,island) comps_in_island
from (
select competition_id, sportsman_id, hold_date , add_months(hold_date,-1*row_number() over(partition by sportsman_id order by hold_date)) island
from result
)
)
where comps_in_island > 1
group by sportsman_id, island, comps_in_island;

DB fiddle: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=1b707262722bc555ad851aee029b347a

-edit
I got confused by some of the data, it looks like it's not the date that's important but the competition_id. This makes it simpler, if you have a gapless competition_id sequence (so competition 65786162213 was 65.7 billion events after 4)

select sportsman_id, min(competition_id) , max(competition_id), comps_in_island
from (
select competition_id, sportsman_id, hold_date, island, count(*) over (partition by sportsman_id,island) comps_in_island
from
select competition_id, sportsman_id, hold_date , competition_id -row_number() over(partition by sportsman_id order by competition_id)) island
from result
)
)
where comps_in_island > 1
group by sportsman_id, island, comps_in_island;

Or if you need to work out the competition numbers first you just need an additional subquery using dense_rank to rank the unique competition_ids accounting for ties :

select sportsman_id, min(competition_id) , max(competition_id), comps_in_island
from (
select competition_id, sportsman_id, hold_date, island, count(*) over (partition by sportsman_id,island) comps_in_island
from (
select competition_id, sportsman_id, hold_date , comp_number -row_number() over(partition by sportsman_id order by comp_number) island
from (
select competition_id, sportsman_id, hold_date , dense_rank() over (partition by null order by competition_id) comp_number
from result
)
)
)
where comps_in_island > 1
group by sportsman_id, island, comps_in_island;

This does assume that every possible competion_id you care about has a row in result.

Oracle 12.2 - Replacement of NOPARTITION feature

The (no)partition option for sequences was never documented. And thus never supported.

There was a bug in 12.1 which exposed this via dbms_metadata. It no longer happens in 12.2

Undocumented features can (and as this proves) do change without warning. Using them is strictly at your own risk.

Oracle partition by group into date based sequence

First you should find GROUP_ID for each record to sort all similar COL1 to different GROUPS if they have a gap between. And then use this GROUP_ID in the OVER statement with COL1:

SQLFiddle demo

SELECT ROW_NUMBER() OVER (PARTITION BY Group_id,col1 ORDER BY col2) AS RNUM, a3.* 
FROM
(
select a1.*,
(select count(*) from t a2 where
a2.col1<>a1.col1
AND
a2.col2<a1.col2) as GROUP_ID
from t a1
) a3

order by col2


Related Topics



Leave a reply



Submit