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

Langage SQL Discussion :

Dénombrement temporel groupé complexe


Sujet :

Langage SQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Par défaut Dénombrement temporel groupé complexe
    Bonjour à tous,

    Je me permets de venir parler d'un petit problème existentiel. Je cherche à dénombrer des éléments suivant une date bien précise (paramètre) et suivant la valeur d'une propriété particulière (fixée).
    Ça permet de répondre à la question "Combien y-en avait-il possédant tel ou tel statut à telle ou telle date?".

    La requête ne concerne qu'une seule table qui possède les champs suivant :
    -id : Identifiant de l'enregistrement (auto_increment, PRIMARY INDEX)
    -create_time (VARCHAR(30)) : Date de création de l'enregistrement sous la forme d'un timestamp UNIX.
    -remove_time (VARCHAR(30)) : Date de suppression du jeu de données sous la forme d'un timestamp UNIX.
    -status_id (INT) : Le statut de l'enregistrement. N valeurs quelconques (la liste des valeurs possibles peut varier d'un enregistrement à un autre).
    -TOSTATUS_N_TIME (VARCHAR(30)) : Date de passage à la valeur "N" du champ status_id. Si il y a les 3 valeurs possibles {"1", "2", "3"} pour tel ou tel enregistrement, on utilisera les champs TOSTATUS_1_TIME, TOSTATUS_2_TIME et TOSTATUS_3_TIME.

    La liste totale des statuts est connue à l'avance mais tous les enregistrements ne sont pas censés utiliser tous les statuts.

    On est donc capable de déterminer les intervalles pendant lesquels le champ status_id a pris telle ou telle valeur.
    La difficulté reviens à reconstituer cette valeur puisque status_id contient la valeur correspondant à l'instant où la requête est faite et non à l'instant qui nous intéresse.

    J'ai tenté de faire l'ébauche d'une requête que voici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    SELECT COUNT(*), (
      SELECT ..... ?????? .....) AS old_status_id
    FROM
      ma_table
    WHERE 
      create_time <= %TIME_RECHERCHE% AND (
        remove_time IS NULL OR 
        remove_time > %TIME_RECHERCHE%
      )
    GROUP BY old_status_id
    Mais je ne suis pas sur que ce soit bien correct. "SELECT ..... ?????? ....." étant une requête imbriquée (dont j'aimerai bien me passer si possible) qui permettrait de reconstituer la valeur du champ status_id prise à %TIME_RECHERCHE%, temps fixé pour la recherche en tant que paramètre.

    Je précise que je souhaite éviter les solutions du genre "N valeurs -> N requêtes" et que je travaille sous MySQL 5

    Est-ce que quelqu'un aurait une idée sur la meilleure manière de procéder. Peut-être que mon modèle de données n'est pas adapté pour cette utilisation mais sa remise en question n'est réellement pas souhaitable

    Merci par avance, bonne journée.

  2. #2
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 454
    Par défaut
    Il manque trop d'information pour qu'on puisse vous répondre, à lire :
    http://www.developpez.net/forums/a69...gage-sql-lire/

  3. #3
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 954
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 954
    Par défaut
    Il y a au moins une chose à changer dans le modèle, c'est le type de donnée de create_time et remove_time.
    Tu ne peux pas stocker un unix timestamp dans un VARCHAR il faut un INT, sinon 01/01/1980 (315554400) sera supérieur au 01/01/2011 (1293861600).

    Mais pourquoi ne pas utiliser le type timestamp (ou date suivant le SGBD) en base, les opérations de manipulations seront nettement plus simples.

  4. #4
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Par défaut
    Merci pour vos réponses.

    En effet j'avoue avoir oublié des choses.

    J'ai rajouté le nom de mon SGBDR dans le post initial : MySQL 5 sous un serveur mutualisé chez OVH.

    Voici une requête qui permettrai de créer une table comme celle que j'évoque :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    CREATE TABLE `infosresnet`.`test` (
      `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
      `create_time` INT UNSIGNED NULL DEFAULT NULL ,
      `remove_time` INT UNSIGNED NULL DEFAULT NULL ,
      `status_id` INT NOT NULL ,
      `TOSTATUS_1_TIME` INT UNSIGNED NULL DEFAULT NULL ,
      `TOSTATUS_4_TIME` INT UNSIGNED NULL DEFAULT NULL ,
      `TOSTATUS_5_TIME` INT UNSIGNED NULL DEFAULT NULL
    ) ENGINE = InnoDB ;
    J'ai dores et déjà pris en compte les modifications du typage des champ contenant des timestamps : j'ai opté pour Int.

    On peut utiliser le dataset suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    INSERT INTO `infosresnet`.`test` (`id`,`create_time`,`remove_time`,`status_id`,`TOSTATUS_1_TIME`,`TOSTATUS_4_TIME`,`TOSTATUS_5_TIME`)
    VALUES (
    NULL , '1181559493', NULL , '1', '1181559493', NULL , NULL
    ), (
    NULL , '1214391493', NULL , '5', '1214477893', '1221908293', '1229770693'
    ), (
    NULL , '1232017093', '1263553093', '4', '1211281093', '1232449093', NULL
    ), (
    NULL , '1214996293', NULL , '1', '1212404293', NULL , NULL
    );
    Enfin, le résultat attendu à la requête que je cherche serait, pour le 09/10/2008 (1223549893) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    status_id     COUNT(*)
    ----------  ------------
    1               3
    4               1
    5               0
    En vous remerciant.

  5. #5
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Par défaut
    Bonjour

    Voici une solution :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
     
    SELECT 1, COUNT(*)
    FROM test
    WHERE TOSTATUS_1_TIME <= 1223549893
    AND (TOSTATUS_4_TIME IS NULL OR TOSTATUS_4_TIME > 1223549893)
    UNION ALL
    SELECT 4, COUNT(*)
    FROM test
    WHERE TOSTATUS_4_TIME <= 1223549893
    AND (TOSTATUS_5_TIME IS NULL OR TOSTATUS_5_TIME > 1223549893)
    UNION ALL
    SELECT 5, COUNT(*)
    FROM test
    WHERE TOSTATUS_5_TIME <= 1223549893


    Mais votre modélisation est... disons... disgracieuse

    A première vue, vous devriez avoir une table paramétre, une table statut, et une table d'historique parametre_statut...

    Comment ferez vous lorsqu'un nouveau statut apparaitera ? vous comptez rajouter une colonne à votre table... et réécrire toutes vos requetes ?

  6. #6
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Par défaut
    Bonjour aieeeuuuuu,

    Citation Envoyé par aieeeuuuuu Voir le message
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
     
    SELECT 1, COUNT(*)
    FROM test
    WHERE TOSTATUS_1_TIME <= 1223549893
    AND (TOSTATUS_4_TIME IS NULL OR TOSTATUS_4_TIME > 1223549893)
    UNION ALL
    SELECT 4, COUNT(*)
    FROM test
    WHERE TOSTATUS_4_TIME <= 1223549893
    AND (TOSTATUS_5_TIME IS NULL OR TOSTATUS_5_TIME > 1223549893)
    UNION ALL
    SELECT 5, COUNT(*)
    FROM test
    WHERE TOSTATUS_5_TIME <= 1223549893
    En effet c'est une des solutions possibles.
    Mais je ne connais pas à l'avance la liste des statut à cibler. Cela dépend de ce qu'il y a effectivement dans la table.
    Par conséquent je comptais plus sur le GROUP BY pour me tirer d'affaire quant à cette liste.

    Mais votre modélisation est... disons... disgracieuse

    A première vue, vous devriez avoir une table paramétre, une table statut, et une table d'historique parametre_statut...

    Comment ferez vous lorsqu'un nouveau statut apparaitera ? vous comptez rajouter une colonne à votre table... et réécrire toutes vos requetes ?
    En effet c'est bien le cas.
    Je ne voulais pas alourdir mon explication avec des clauses relationnelles mais peut-être que cela aidera finalement à trouver une solution plus abordable.
    Les "champs" TOSTATUS_N_TIME sont dans une table annexe (en réalité des lignes de paires clé/valeur) et reliée à la table principale par une table annexe à deux colonnes faisant référence à la fois à la table principale et à la table contenant TOSTATUS_N_TIME.
    On appelle ca une CIF je crois.

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/02/2015, 14h57
  2. Enlever des sprites à un groupe et formes complexes
    Par Bénarès77 dans le forum Programmation multimédia/Jeux
    Réponses: 5
    Dernier message: 14/10/2011, 22h58
  3. Requète Complexe avec GROUP BY et classement descendant
    Par snoups58 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 13/10/2008, 18h44
  4. Réponses: 6
    Dernier message: 14/06/2008, 17h46
  5. Création d'une vue sous SQL Server - group by complexe
    Par csembeil dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 12/01/2006, 16h17

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