Wir haben eine Tabelle von Werten, die in eine de-normalisierte Menge erweitert wurde, und ich muss es neu zu normalisieren, die niedrigste Anzahl von Referenzsätzen finden.Oracle konsolidieren oder re-normalisieren Zeilensätze
Eine vereinfachte Version der Quelldaten wie folgt aussieht etwas:
Period Group Item Seq
------ ----- ---- ---
1 A 1 1
1 A 2 2
1 A 3 3
1 B 1 1
1 B 2 2
1 B 3 3
1 C 1 1
1 C 4 2
1 C 5 3
1 D 2 1
1 D 1 2
1 D 3 3
1 E 1 1
1 E 2 2
1 F 2 1
1 F 1 2
1 F 3 3
ich die minimale Anzahl der Listen in den Daten definiert extrahieren möchten und einen Verweis auf die auf Zeit und Gruppe basierte Liste zuweisen. Eine Liste besteht aus einer geordneten Sequenz von Elementen. Hier sind die 4-Listen in der obigen Daten definiert:
List Item Seq
---- ---- ---
1 2 1
1 1 2
1 3 3
2 1 1
2 2 2
2 3 3
3 1 1
3 4 2
3 5 3
4 1 1
4 2 2
und die Ausgabe, die ich erreichen möchte:
Period Group List
------ ----- ----
1 A 2
1 B 2
1 C 3
1 D 1
1 E 4
1 F 1
Ich habe eine Lösung, die mit ORA_HASH und LIST_AGG arbeitet einen Hash über die erzeugen Elemente der Gruppe, aber es schlägt fehl, wenn die Anzahl der Elemente in einer Gruppe größer als 400 ist. Der resultierende Fehler ist ORA-01489: Das Ergebnis der Verkettung von Strings ist zu lang.
Ich suche nach einer allgemeinen Lösung, die unabhängig von der Anzahl der Elemente in einer Gruppe in einem bestimmten Zeitraum funktionieren würde.
Elemente werden durch einen ganzzahligen Wert unter 100.000 gekennzeichnet. Realistisch werden wir nie mehr als 4000 Artikel in einer Gruppe sehen.
Dies ist logisch ähnlich dem, was funktioniert für bis zu 400 Gruppenelement Datensätze:
WITH
the_source_data as (
select 1 as the_period, 'A' as the_group, 1 as the_item, 1 as the_seq from dual union
select 1 as the_period, 'A' as the_group, 2 as the_item, 2 as the_seq from dual union
select 1 as the_period, 'A' as the_group, 3 as the_item, 3 as the_seq from dual union
select 1 as the_period, 'B' as the_group, 1 as the_item, 1 as the_seq from dual union
select 1 as the_period, 'B' as the_group, 2 as the_item, 2 as the_seq from dual union
select 1 as the_period, 'B' as the_group, 3 as the_item, 3 as the_seq from dual union
select 1 as the_period, 'C' as the_group, 1 as the_item, 1 as the_seq from dual union
select 1 as the_period, 'C' as the_group, 4 as the_item, 2 as the_seq from dual union
select 1 as the_period, 'C' as the_group, 5 as the_item, 3 as the_seq from dual union
select 1 as the_period, 'D' as the_group, 2 as the_item, 1 as the_seq from dual union
select 1 as the_period, 'D' as the_group, 1 as the_item, 2 as the_seq from dual union
select 1 as the_period, 'D' as the_group, 3 as the_item, 3 as the_seq from dual union
select 1 as the_period, 'E' as the_group, 1 as the_item, 1 as the_seq from dual union
select 1 as the_period, 'E' as the_group, 2 as the_item, 2 as the_seq from dual union
select 1 as the_period, 'F' as the_group, 2 as the_item, 1 as the_seq from dual union
select 1 as the_period, 'F' as the_group, 1 as the_item, 2 as the_seq from dual union
select 1 as the_period, 'F' as the_group, 3 as the_item, 3 as the_seq from dual
),
cte_list_hash as (
select
the_period,
the_group,
ora_hash(listagg(to_char(the_item, '00000')||to_char(the_seq, '0000')) within group (order by the_seq)) as list_hash
from
the_source_data
group by
the_period,
the_group
),
cte_unique_lists as
(
select
list_hash,
min(the_period) keep (dense_rank first order by the_period, the_group) as the_period,
min(the_group) keep (dense_rank first order by the_period, the_group) as the_group
from
cte_list_hash
group by
list_hash
),
cte_list_base as
(
select
the_period,
the_group,
list_hash,
rownum as the_list
from
cte_unique_lists
)
select
A.the_period,
A.the_group,
B.the_list
from
cte_list_hash A
inner join
cte_list_base B
on A.list_hash = B.list_hash;
Jede Hilfe in die richtige Richtung zu finden, diese zu ergreifen, würde sehr geschätzt werden.
Dank Matthew, das funktioniert perfekt und schnell genug auf die Anzahl der Zeilen, die wir in der Tabelle haben. Kudos! –