IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Administration Oracle Discussion :

Regroupement par plage de données consécutives.


Sujet :

Administration Oracle

  1. #1
    Candidat au Club
    Inscrit en
    Novembre 2006
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 2
    Points : 2
    Points
    2
    Par défaut Regroupement par plage de données consécutives.
    Bonjour à vous,

    Je cherche a savoir comment réaliser un regroupement un peu particulier en SQL.
    Pour exemple, j'ai une table tel que:

    Journée de l'année / température moyenne
    120 / 21
    121 / 23
    122 / 21
    123 / 21
    124 / 21
    125 / 23
    126 / 23

    Je souhaiterais obtenir le résultat suivant:
    JournéeDeb / JournéeFin / Température
    120 / 120 / 21
    121 / 121 / 23
    122 / 124 / 21
    125 / 126 / 23

    et non pas (comme je l'obtient en regroupant sur les températures et les min / max des journée):
    120 / 124 / 21
    121 / 126 / 23

    J'espère être compréhensible et remercie par avance tous ceux qui voudrons bien m'éclairer.

    NT

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2002
    Messages : 238
    Points : 125
    Points
    125
    Par défaut
    voilà

    j'ai passé mon temps à trouver une solution 'pas très simple'
    mais ça fonctionne

    NB : En espérant que la table des "JOURS" ne soit pas pas énorme !
    REM : A modifier pour le faire par année

    Prévenez si c'est OK,sinon bon courage...
    A+

    SOLUTION ci-dessous :
    ---------------------------
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    --
    -- vue : qui pour l'exemple sert de TABLE
    --
    CREATE OR REPLACE VIEW v_day (day,deg)
    AS
    select 120,21 from dual
    union select 121,23 from dual
    union select 122,21 from dual
    union select 123,21 from dual
    union select 124,21 from dual
    union select 125,23 from dual
    union select 126,23 from dual
    /
    --
    -- vue intermédaire : comprenant les couples de jours de même degré
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE OR REPLACE VIEW v_day_same_deg 
        (day,deg_idem_day,deg )
    AS
    select    a.day,b.day,a.deg
        from  v_day a,v_day b
        where a.deg=b.deg and a.day!=b.day
         and a.day<=b.day
    /
    --
    -- Fonction ramenant le jour(max) d'un range complet
    -- pour un jour de la "table" (et son "degré")
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    CREATE OR REPLACE
    function f_range(P_day number,p_deg number)
    return number
    is
     cur_day   number := p_day;
     cur_deg   number := p_deg;
     next_day  number := null;
     next_deg  number := null;
    begin
    loop
    begin
        select    v.day,v.deg  into next_day,next_deg
             from v_day v
            where v.day=cur_day+1 and v.deg=cur_deg;
        cur_day:=next_day;
        cur_deg:=next_deg;
        exception when others then null;
        exit when (sql%rowcount=0);
    end;
    end loop;
    return cur_day;
    end;
    /
    --
    -- vue qui exécute la fonction pour tous les jours de la 'table'
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    create or replace view v_day_range 
    (
    day,deg,day_sup_idem_deg
    )
    as
     SELECT
        DAY,
        DEG,
        f_range(DAY,DEG)
     FROM v_day
    /
    --
    -- vue finale
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    create or replace view v_day_final 
    (
    text
    )
     as
     select
     day||' / '||day_sup_idem_deg||' : '||deg  from v_day_range  where day!=day_sup_idem_deg
     union
     select
     day||' / '||day||' : '||deg from V_DAY
         where day  not in (select deg_idem_day from v_day_same_deg)
    /

  3. #3
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut regroupement par plages
    Je te propose une solution ensembliste (à partir de la vue proposée par lediz) :

    - les débuts de plage sont facile à repérer, ce sont les jours (J) pour lesquels hier (H) avait une température différente (ou bien il n'y a pas d'hier du tout, afin de ne pas éliminer le premier jour de ton calendrier) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT J.day, J.deg
    FROM v_day J
      LEFT JOIN v_day H ON J.day = H.day + 1 
    WHERE J.deg <> H.deg OR H.day IS NULL;
    - les fins de plage sont les jours pour lesquels demain (D) a une température différente... :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT J.day, J.deg
    FROM v_day J
      LEFT JOIN v_day D ON J.day = D.day - 1
    WHERE J.deg <> D.deg OR D.day IS NULL;
    Il n'y a plus qu'à tout trier et replacer dans l'ordre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    SELECT deb2.day Debut, fin2.day Fin, deb2.deg Temp
    FROM (
      SELECT day, deg, ROWNUM
      FROM (SELECT J.day, J.deg
        FROM v_day J
          LEFT JOIN v_day H ON J.day = H.day + 1 
        WHERE J.deg <> H.deg OR H.day IS NULL
        ORDER BY J.day 
        ) deb1 
      )  deb2
    INNER JOIN
      (SELECT day, ROWNUM
      FROM (SELECT J.day
        FROM v_day J
          LEFT JOIN v_day D ON J.day = D.day - 1
        WHERE J.deg <> D.deg OR D.day IS NULL
        ORDER BY J.day  
        ) fin1
      ) fin2
    ON deb2.ROWNUM = fin2.ROWNUM
    --
    Antoun

    Guide complet MySQL 5, par Antoine Dinimant, éd. MicroApplication
    http://www.microapp.com/livre_mysql_7873.html
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  4. #4
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 073
    Points
    19 073
    Par défaut
    Merci de penser aux balises code à l'avenir

  5. #5
    Rédacteur

    Inscrit en
    Septembre 2004
    Messages
    626
    Détails du profil
    Informations forums :
    Inscription : Septembre 2004
    Messages : 626
    Points : 848
    Points
    848
    Par défaut
    Bonjour,

    On peut procéder de manière plus directe avec les fonctions analytiques lead et lag :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    select 
       start_group, 
       end_group, deg
    from
       (
          select   
             day, 
             deg, 
             start_group, 
             case 
                when end_group is null then lead(end_group) over(order by day) 
             else 
                end_group 
             end end_group
          from
             (
                select
                   day, 
                   deg, 
                   -- detection des changements de groupes de jours consecutifs de meme temperature
                   case 
                      when nvl(lag(deg) over(order by day), -1) <> deg then day 
                   end start_group,
                   case 
                      when nvl(lead(deg) over(order by day), -1) <> deg then day 
                   end end_group
                from   
                   TEST
             )
          where 
             -- filtre pour ne garder
             -- que les jour debuts ou fin de groupe
             start_group is not null or 
             end_group is not null
       )
    where 
       start_group is not null and 
       end_group is not null
    Ce qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    START_GROUP  END_GROUP        DEG
    ----------- ---------- ----------
            120        120         21
            121        121         23
            122        124         21
            125        126         23

    Laly.
    In the heart of the truly greats, perfection is never achieved but endlessly pursued.

    Mon article sur les fonctions analytiques d'Oracle (calcul de moyennes mobiles, de quartiles et bien d'autres...)

  6. #6
    Candidat au Club
    Inscrit en
    Novembre 2006
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 2
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    Merci a tous pour vos propositions!
    Je suis plus que satisfait. Il me semble que l'opération que je souhaite réaliser n'est pas prévue dans le cadre d'une simple exploitation de données.
    Les deux premiers exemples montrent bien que SQL n'est fait pour ça. En revanche je ne connaissais pas les fonctions analytiques! C'est trés intéressant.
    Je vais m'y plonger dés a présent. Cependant j'avais posté ce message dans un forum général SQL et comme j'ai négligé de préciser que j'utilisais SQLSERVER2k je me retrouve ici. En tout cas merci beaucoup d'avoir trouver une solution a mon probleme.

    NT

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 16/06/2014, 09h22
  2. [XL-2010] VBA pour extraire plage de donnée excel et envoyer par mail
    Par Couettecouette dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 03/01/2013, 21h09
  3. Réponses: 2
    Dernier message: 05/03/2009, 10h19
  4. Réponses: 4
    Dernier message: 11/08/2008, 15h29
  5. Regroupement par mois
    Par fplanglois dans le forum SQL
    Réponses: 7
    Dernier message: 29/07/2003, 16h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo