2017-04-11 6 views
0

Ich formuliere meine vorherige Frage neu, wie von einem Kommentator vorgeschlagen.Die längste geordnete Liste innerhalb einer ungeordneten Liste finden

Das folgende Set repräsentiert den Verkauf eines Produkts in aufeinanderfolgenden Wochen.

22,19,20,23,16,14,15,15,18,21,24,10,17 

Ich brauche die längste Abfahrt der höheren Verkaufszahlen in aufeinander folgenden Wochen zu finden, das heißt Wochen 6 bis Woche-11 durch 14,15,15,18,21,24 vertreten.

Ich habe eine Abfrage, die das Ergebnis zurückgibt, aber möchte die Methoden kennen, um es zu verbessern. Kann mir jemand bitte etwas vorschlagen? Danke im Voraus.

with 
raw_data (sales) as 
(
    select '22,19,20,23,16,14,15,15,18,21,24,10,17' from dual 
) 
, 
derived_tbl(week, sales) as 
(
    select level, regexp_substr(sales, '([[:digit:]]+)(,|$)', 1, level, null, 1) 
    from raw_data connect by level <= regexp_count(sales,',')+1 
) 
, 
coll(week, sales, salesdlag, salesdlead) as 
(
    select week, sales, 
    nvl(sales - (lag(sales) over (order by week)), 0), 
    nvl((lead(sales) over (order by week) - sales), 0) 
    from derived_tbl 
) 
, 
filt_coll(week, sales, salesdlag, salesdlead) as 
(
    select week, sales, salesdlag, salesdlead 
    from coll 
    where not (salesdlag < 0 and salesdlead < 0) 
) 
, 
cte(startweek, sales, salesdlag, salesdlead, actualweek) as 
(
    select week, sales, salesdlag, salesdlead, week from filt_coll 
    union all 
    select cte.startweek, cl.sales, cl.salesdlag, cl.salesdlead, cl.week 
    from filt_coll cl, cte 
    where cl.week = cte.actualweek + 1 and cl.sales >= cte.sales 
) 
, 
pen_coll as 
(
    select * from cte order by startweek,actualweek 
) 
, 
final_coll as 
(
    select startweek, actualweek, sales, count(startweek) over(PARTITION BY startweek) as cnt from pen_coll 
) 
select LISTAGG(sales, ',') within group (order by null) as rslt 
from final_coll 
where cnt = (select max(cnt) from final_coll) 
; 
+0

Warum sind Sie es als eine durch Kommas getrennte Zeichenfolge und nicht in einer [Sammlung] Speichern (https : //docs.oracle.com/cd/B28359_01/appdev.111/b28370/collections.htm#LNPLS005)? – MT0

Antwort

0

eine Sammlung verwenden (anstelle einer getrennten String), um die Werte zu speichern und Sie können auch eine hierarchische Abfrage verwenden, um die Ergebnisse zu finden:

SELECT * 
FROM (
    SELECT TRIM(LEADING ',' FROM SYS_CONNECT_BY_PATH(value, ',')) AS week_values, 
     CONNECT_BY_ROOT id AS first_week, 
     id AS last_week, 
     LEVEL AS num_weeks, 
     MAX(LEVEL) OVER() AS max_weeks 
    FROM (
    SELECT COLUMN_VALUE AS value, 
      ROWNUM As id 
    FROM TABLE(SYS.ODCINUMBERLIST(22,19,20,23,16,14,15,15,18,21,24,10,17)) 
) 
    WHERE CONNECT_BY_ISLEAF = 1 
    CONNECT BY PRIOR id + 1 = id AND PRIOR value <= value 
) 
WHERE num_weeks = max_weeks 

Ausgang:

WEEK_VALUES  FIRST_WEEK LAST_WEEK NUM_WEEKS MAX_WEEKS 
----------------- ---------- --------- --------- --------- 
14,15,15,18,21,24   6  11   6   6 

Sie können die hierarchische Abfrage weiter so einschränken, dass sie nur startet, wenn der vorherige Wert größer ist:

SELECT * 
FROM (
    SELECT TRIM(LEADING ',' FROM SYS_CONNECT_BY_PATH(value, ',')) AS week_values, 
     CONNECT_BY_ROOT id AS first_week, 
     id AS last_week, 
     LEVEL AS num_weeks, 
     MAX(LEVEL) OVER() AS max_weeks 
    FROM (
    SELECT COLUMN_VALUE AS value, 
      LAG(COLUMN_VALUE) OVER (ORDER BY ROWNUM) AS prev_value, 
      ROWNUM As id 
    FROM TABLE(SYS.ODCINUMBERLIST(22,19,20,23,16,14,15,15,18,21,24,10,17)) 
) 
    WHERE CONNECT_BY_ISLEAF = 1 
    START WITH prev_value IS NULL OR prev_value > value 
    CONNECT BY PRIOR id + 1 = id AND PRIOR value <= value 
) 
WHERE num_weeks = max_weeks 

aktualisieren

Oracle Setup:

create table tst(id, value) as 
    select rownum, round(dbms_random.value*9) 
    from dual 
    connect by level <= 10000; 

Abfrage:

SELECT * 
FROM (
    SELECT TRIM(LEADING ',' FROM SYS_CONNECT_BY_PATH(value, ',')) AS week_values, 
     CONNECT_BY_ROOT id AS first_week, 
     id AS last_week, 
     LEVEL AS num_weeks, 
     MAX(LEVEL) OVER() AS max_weeks 
    FROM (
    SELECT value, 
      LAG(value) OVER (ORDER BY id) AS prev_value, 
      id 
    FROM tst 
) 
    WHERE CONNECT_BY_ISLEAF = 1 
    START WITH prev_value IS NULL OR prev_value > value 
    CONNECT BY PRIOR id + 1 = id AND PRIOR value <= value 
) 
WHERE num_weeks = max_weeks 
+0

Ich fange gerade an, über die grundlegenden Auswahlanweisungen hinaus zu lernen. Ich wusste nichts über Sammlungen. Sie haben mir eine Reihe von Tipps gegeben, um zu lernen. Danke vielmals. – Slkrasnodar

+0

versucht, die Sammlung durch eine Ergebnismenge von 'create table tst (id, value) as zu ersetzen (wählen Sie rownum, round (dbms_random.value * 9) von Dual Connect nach Ebene <= 10000);' table. Scheint nicht zu mögen ... – Slkrasnodar

+0

@Slkrasnodar Habe ein Update hinzugefügt, das hoffentlich funktionieren würde (aber momentan nicht testen). – MT0

Verwandte Themen