Forum Programmation.SQL Modifier le schema dynamiquement

Posté par . Licence CC by-sa
Tags : aucun
-1
9
déc.
2014

Bonjour,
Je travaille sur une appli où tous les mois on doit faire des calculs pour tous les élément d'une table et les stocker en base de données (MySQL).
Quel est le plus intéressant, modifier le schéma de la base, ajouter une colonne et y stocker le résultat des calculs ou crée une nouvelle table (id_objet, mois, résultat).
Il ne devrait pas être possible de pouvoir lancer les calculs plusieurs fois en même temps, il ne devrait donc pas y avoir de conflit quelque soit le modèle choisi.

Ça me fait bizarre de modifier le schéma (n'y a-t-il pas de risque de corruption des données ?) mais je ne m'y connais pas assez.

Merci d'avance.

  • # Ni l'un ni l'autre

    Posté par . Évalué à 2.

    Au vu des colonnes choisies, à savoir :

    (id_objet, mois, résultat)

    il suffit d'insérer au fil des mois les résultats dans la même table, sans modifier sa structure (sinon mois deviendrait faux), ni créer de nouvelle table (sinon mois n'aurait plus de sens).

  • # Table

    Posté par (page perso) . Évalué à 2.

    Clairement, avec les éléments que tu nous donnes, les deux approches sont faisables.

    Maintenant, d'un point de vue personnel, je choisirais la création d'une nouvelle table car ça ne me semble pas pertinent ici de modifier le schéma de la bd.

    Et puis, se sera plus facile pour réaliser des statistiques par exemple, ou suivre des évolutions, etc… Les requêtes seront plus simple ;)

    • [^] # Re: Table

      Posté par . Évalué à 1.

      Hello,

      Clairement, avec les éléments que tu nous donnes, les deux approches sont faisables.

      Elles sont faisables, mais aucune ne me semble raisonnable, comme je disais dans mon commentaire ci-dessus :) Ca détruit l'intérêt de la colonne "mois" à chaque fois. Or, s'il est là, c'est qu'il y a peut-être une raison.

      A la limite, ce qui me semblerait raisonnable s'il y a besoin de stocker les résultats sur plus d'une année, c'est altérer la table une bonne fois pour toute, pour rajouter une colonne année (voir un vrai champ date au lieu de deux colonnes… mais bon :) ça, c'est que du design !)

      Là on pourrait éventuellement faire des stats en tranchant par mois, année, etc.

      Mais les deux autres options vont en dépit du bon sens d'une base de donnée à mon avis (je ne suis ni SGBD admin, ni dans la mouvance noSQL, donc je peux me gourer sur les tendances modernes, hein !).

      • [^] # Re: Table

        Posté par (page perso) . Évalué à 1.

        Je comprends pourquoi on est en désaccord :)

        Alors, dans ma tête, le mois était un mois "relatif" par rapport à une date de référence. Ainsi, au bout de 10 ans, on est au mois 120 (mais j'admet que c'était loin d'être clair dans mon message :) ).

        Et ainsi, on a bien une seule table qui contient l'intégralité des données calculées.

        Mais les deux autres options vont en dépit du bon sens d'une base de donnée à mon avis (je ne suis ni SGBD admin, ni dans la mouvance noSQL, donc je peux me gourer sur les tendances modernes, hein !).

        La première clairement.

        La seconde, ça dépend comment on interprète le propos initial. Tel que je l'ai compris, son idée était de faire une table contenant toutes les données, et non rajouter des tables au fur et à mesure. Mais c'est vrai que c'est pas clair et que les deux interprétations sont possibles. Du coup, si c'est ajouter des tables au fur et à mesure, c'est pas top non plus.

        A moins d'avoir besoin d'un niveau méta, toucher le schéma d'une bd dynamiquement est en général une mauvaise idée.

        • [^] # Re: Table

          Posté par . Évalué à -2.

          Ainsi, au bout de 10 ans, on est au mois 120

          Compter les mois en base 10, c'est rude. Très rude. Y'en a 12 quand même !

          Compter sans prévoir plus de 10 ans, c'est encore plus rude :)

          Je ne suis ni DBA ni le client final, mais je doute un peu de la manière de procéder, là. :p

          • [^] # Re: Table

            Posté par (page perso) . Évalué à 2.

            Compter les mois en base 10, c'est rude. Très rude. Y'en a 12 quand même !

            Moi pas comprendre ! Ca te gène de dire que 10 ans c'est 120 mois ? Pourtant, c'est classique. 12 mois, 24 mois. On trouve ça pour les prêts par exemple, ou souvent aussi dans les contrats ;)

            Compter sans prévoir plus de 10 ans, c'est encore plus rude :)

            J'ai pris 10 ans pour l'exemple. Mais si on utilise un INT pour représenter le nombre de mois, ça fait déjà un beau paquet d'années :p

            Je ne suis ni DBA ni le client final, mais je doute un peu de la manière de procéder, là. :p

            Le client final n'a pas besoin de connaitre la représentation des données (à moins que cela ne soit dans le cahier des charges). Ensuite, pour la manière de procéder, en quoi est-ce que cela te gêne ? Est-ce parce que c'est "inhabituel" comme représentation ?

            • [^] # Re: Table

              Posté par . Évalué à -2.

              Moi pas comprendre ! Ca te gène de dire que 10 ans c'est 120 mois

              En base 10 comme proposée, oui, très fortement.

              Comment différencier octobre de l'an 0 (10) de janvier de l'an 1 (10) ? Par du padding ? Super pour les requètes SQL…

              • [^] # Re: Table

                Posté par (page perso) . Évalué à 2.

                C'est toi qui parle de base 10. 1 an = 12 mois. 10 ans = 120. Il n'y a pas de soucis.

                octobre de l'an 0 = 10
                janvier de l'an 1 = 13

                Je ne vois pas où est le problème ;)

                • [^] # Re: Table

                  Posté par . Évalué à -2. Dernière modification le 09/12/14 à 23:59.

                  Je ne vois pas où est le problème ;)

                  Agrège moi les stats de janvier de toutes les années 0-9.

                  En SQL, hein ;)

                  Et déjà, tu vois que tu as un problème, tu dois passer à 13, et pas 12*10…

                  • [^] # Re: Table

                    Posté par (page perso) . Évalué à 1. Dernière modification le 10/12/14 à 00:16.

                    Agrège moi les stats de janvier de toutes les années 0-9.
                    En SQL, hein ;)

                    L'opérateur modulo est ton ami ;)

                    Et déjà, tu vois que tu as un problème, tu dois passer à 13, et pas 12*10…

                    Je ne comprends vraiment pas ton propos. Pourquoi 12*10 ???

                    edit: je crois que je viens de comprendre. Tu voudrais un truc du genre YYYYM, où M est le mois, et YYYY des années ? C'est ça ?

                    • [^] # Re: Table

                      Posté par . Évalué à -3.

                      Hello,

                      L'opérateur modulo est ton ami ;)

                      Allons-y alors. Je sens qu'on va se marrer, rien que juste le calendrier rien que Julien.

                      A toi l'honneur !

                      Y'a au moins quatre modulos à faire.

                      Tu voudrais un truc du genre YYYYM, où M est le mois, et YYYY des années ?

                      Non, je dis que c'est encore plus compliqué que ça.

                      • [^] # Re: Table

                        Posté par (page perso) . Évalué à 2.

                        Compter les jours, c'est galère. Compter les mois, non. Car une année = 12 mois et on en parle plus.
                        Pour les jours, avec les années bisextiles, etc… c'est effectivement le bazard de compter les années et les mois.

                        Donc non, il n'y a qu'un seul modulo à faire.

                        Et je ne vois vraiment pas le problème que tu veux soulever. Si c'est plus compliqué que cela, expose clairement la situation. Donne un exemple. Que signifie ton 12*10 de ton commentaire précédent ?? Etc…

                        Cette solution de compter les mois, j'ai eu à la mettre en place pour un client qui voulait des stats sur ses années comptables (différentes des années civiles dans son cas). Et franchement, c'était d'une facilité déconcertante avec cette méthode ;)

                      • [^] # Re: Table

                        Posté par (page perso) . Évalué à 2.

                        Agrège moi les stats de janvier de toutes les années 0-9.
                        En SQL, hein ;)

                        Et pour te montrer à quel point c'est simple

                        SELECT SUM(stat) FROM ma_table WHERE mois % 12 = 0 AND mois <= 9*12

                        avec une hypothèse : c'est que le mois de référence, c'est le mois de janvier de l'année 0.

                        • [^] # Re: Table

                          Posté par . Évalué à -4.

                          avec une hypothèse : c'est que le mois de référence, c'est le mois de janvier de l'année 0.

                          Super. Ça ne me donne rien.

                          Donc ta somme fait les sommes quelques soient les années (en gros).

                          Moi je te demande le diff par années. Pour savoir si en hyper décideur je prend les bons choix.

                          Et j'ai toujours un doute sur ton SUM() mais bon.

                          • [^] # Re: Table

                            Posté par (page perso) . Évalué à 5.

                            Sérieusement, après ce message, j'arrête. Je ne prends plus la peine de te répondre à moins que :
                            1) tu sois précis ;
                            2) tu sois concis ;
                            3) tu expliques clairement.

                            Reprennons donc.

                            Super. Ça ne me donne rien.
                            Donc ta somme fait les sommes quelques soient les années (en gros).

                            C'est pourtant ce que tu m'as demandé en l'écrivant avec des mots en français. Tu veux qu'on fasse l'analyse de ta phrase ? Demander d'agréger les résultats sur les années de 0 à 9 et demander des résultats par année pour les années de 0 à 9, c'est complètement différents.

                            Moi je te demande le diff par années. Pour savoir si en hyper décideur je prend les bons choix.

                            Excercice hautement difficile pour toi (vu que tu ne comprends rien). GROUP BY avec une division entière. Tu as 4h (je fais ça en 10s perso).

                            Et j'ai toujours un doute sur ton SUM() mais bon.

                            C'est ton problème, pas le mien. Tu as des doutes, tu testes et tu reviens avec des résultats. Pas avec un avis fait au doigt mouillé sur un domaine que tu ne maitrises pas car cela te semble bizarre.

                            Sur ce, à bon entendeur, bye !

  • # effaré

    Posté par (page perso) . Évalué à 2.

    Je suis pas un spécialiste, mais je lis les réponses et je suis effaré…. il est possible de faire avec le numéro de mois (relatifs), comme il est possible de faire avec une colonne année. Je vais prendre l'exemple du spécialiste qui nous explique qu'avec modulo c'est trop vachement compliqué, voir impossible.

    create table bar (`month` int, `number` int); 
    insert into bar values (1,50);
    insert into bar values (2,30);
    insert into bar values (13,30);
    insert into bar values (14,10);
    insert into bar values (15,14);
    insert into bar values (25,11);
    
    mysql> select * from bar;                
    +-------+--------+      
    | month | number |      
    +-------+--------+      
    |     1 |     50 |      
    |     2 |     30 |      
    |    13 |     30 |      
    |    14 |     10 |      
    |    15 |     14 |      
    |    25 |     11 |      
    +-------+--------+      
    6 rows in set (0.00 sec)
    
    # admettons que janvier soir le 1 (et donc le 13 et 25) et que l'on veuille tous les janvier 
    #(soit 50+30+11) 91 :
    
    mysql> select sum(number) from bar where (mod(month,12)=1 and month > 12) or month=1 ;
    +-------------+
    | sum(number) |
    +-------------+
    |          91 |
    +-------------+
    1 row in set (0.00 sec)

    Une seule requête.

    bonus, ca marche avec février 30+10=40

    mysql> select sum(number) from bar where (mod(month,12)=2 and month > 12) or month=2 ;
    +-------------+
    | sum(number) |
    +-------------+
    |          40 |
    +-------------+
    1 row in set (0.00 sec)

    Maintenant il faut voir la suite de l’application pour décider c'est bien ou pas, mais cela permet de faire des moyennes glissants facilement sur x mois consécutifs par exemple : where month in (25,26,27,28)…

    • [^] # Re: effaré

      Posté par . Évalué à 1.

      Salut,

      Maintenant il faut voir la suite de l’application pour décider c'est bien ou pas,

      Béh oui. Mais si c'est une moyenne glissante, c'est différent d'une moyenne tout court.

      Mais pour l'instant on parle de modifier un schéma SQL.

      Encore une fois, je ne suis pas gestionnaire de SGBD :)

      • [^] # Re: effaré

        Posté par (page perso) . Évalué à 2.

        je repose mon commentaire perdu dans les limbes…

        ajout : il y a aussi la moyenne par mois qui est une moyenne tout court…. c'est bonus la glissante.

        Je vais le faire par année :

        mysql> insert into bar values (27,10);
        Query OK, 1 row affected (0.00 sec)   
        
        mysql> select month,number,truncate(month/12,0) from bar;
        +-------+--------+----------------------+                
        | month | number | truncate(month/12,0) |                
        +-------+--------+----------------------+                
        |     1 |     50 |                    0 |                
        |     2 |     30 |                    0 |                
        |    13 |     30 |                    1 |                
        |    14 |     10 |                    1 |                
        |    15 |     14 |                    1 |                
        |    25 |     11 |                    2 |                
        |    27 |     10 |                    2 |                
        +-------+--------+----------------------+                
        7 rows in set (0.02 sec)                                 
        
        mysql> select month,sum(number),truncate(month/12,0) as annee from bar group by annee;
        +-------+-------------+-------+
        | month | sum(number) | annee |
        +-------+-------------+-------+
        |     1 |          80 |     0 |
        |    13 |          54 |     1 |
        |    25 |          21 |     2 |
        +-------+-------------+-------+
        3 rows in set (0.00 sec)

        et méga bonus

        mysql> select month,sum(number),2011+truncate(month/12,0) as annee from bar group by annee;
        +-------+-------------+-------+
        | month | sum(number) | annee |
        +-------+-------------+-------+
        |     1 |          80 |  2011 |
        |    13 |          54 |  2012 |
        |    25 |          21 |  2013 |
        +-------+-------------+-------+
        3 rows in set (0.00 sec)

        Et là on a la moyenne par année (janvier-décembre). on ne modifie pas un schéma de table à la volée,les BDD sont faite pour enregistré les données en LIGNES.

        Cela me déprime de lire tout et n'importe quoi sur des forums et des péquins sont renvoyés avec des fausses réponses en pensant parler à des mecs qui s'y connaissent un peu… c'est triste.

        Moi non plus je suis pas admin de BDD, mais je réponds pas à tort et à travers.

        • [^] # Re: effaré

          Posté par . Évalué à -2.

          Hello,

          c'est bonus la glissante.

          C'est pas encore ça pour la glissante. Mais bon :)

          Disons que c'est mieux. Enfin, c'est infaisable en SQL… donc de toute façon…

          • [^] # Re: effaré

            Posté par (page perso) . Évalué à 5.

            Q"est-ce qui est impossible à faire ?

            j'ai fais la somme pour que ce soit facile à lire, mais si met avg(), au lieu de sum(), tu auras la moyenne.

            Je crois qu'on ne se comprends pas.

    • [^] # Re: effaré

      Posté par (page perso) . Évalué à 3.

      Entièrement d'accord avec toi.

      Je ne lis plus les avis de kaos, il est complètement à côté de la plaque et ne sait pas de quoi il parle. Pour preuve, son incapacité à dire les choses clairement et à donner des exemples de choses "impossibles".

      En tout cas, merci pour les exemples, ça vient parfaitement illustré l'utilisation de la table id/mois/valeur :)

  • # modifier le schéma dynamiquement ou modifier le schéma tout court ?

    Posté par . Évalué à 4.

    Il y a une petite ambiguïté sur le titre de ta question, et ce n'est pas anodin. Modifier le schéma (le faire évoluer ponctuellement pour faire face à des nouveaux besoins), c'est une opération relativement courante. Modifier dynamiquement le schéma (l'application utilise directement des commandes de DDL[1] pour modifier le schéma à la volée), c'est plutôt casse gueule.

    Dans ton cas, je pense qu'il s'agit de modifier ponctuellement la structure de la base de données. L'ajout d'une table ou d'un champ dans une table n'est a priori pas susceptible d'entraîner une corruption des données, ce qui n'interdit pas de faire une sauvegarde ponctuelle avant la modification (parce que c'est de toute façon une bonne pratique).

    Je trouve difficile de juger de la pertinence d'ajouter une colonne ou une table dans ton cas, parce que ça dépend des enjeux à long terme. Si la donnée calculée n'a vraiment de sens fonctionnel qu'à un instant T, donc que conserver les calculs des mois précédents n'a aucun intérêt, une simple colonne pourrait suffire. Si l'évolution de cette donnée dans le temps est fonctionnellement intéressante, ajouter une table peut être intéressant.

    Bref, modifier ponctuellement la structure de la base de donnée pour répondre à un nouveau besoin est une opération tout à fait classique. Les moteurs de gestion de base de données sont fait pour ça, pas de problème.

    Ajouter une table ou une colonne semblent permettre de répondre au besoin. Chaque solution a ses avantages et inconvénients.

    1.Ajout de colonne :

    • avantages :
      • structure de donnée plus simple
      • interface de visualisation des données plus simple
    • inconvénient :
      • idéalement, il faut trouver un moyen d'indiquer à l'utilisateur la date des derniers calculs, pour ne pas l'induire en erreur (par exemple en début de mois)
      • (inconvénient potentiel) pas d'historisation

    2.Ajout de table :

    • avantages :
      • données historisées
    • inconvénients :
      • structure plus complexe
      • (inconvénient potentiel) interface de visualisation plus complexe si on veut présenter les données historisées à l'utilisateur

    Re bref (hmmm pas si sûr que ça soit bref :D ) : Modifier la structure de donnée est une manipulation techniquement anodine. Dans ton cas, les deux solutions (ajout de table ou ajout de colonne) permettent une réponse technique à ta question. Du coup, le choix entre ces deux solutions ne peut pas se faire sur un critère purement technique. C'est donc en regardant le contexte global de l'application qu'il faudra choisir entre ces deux solutions.

    D'autre part, si les calculs sont suffisamment simples et les données pas trop volumineuses, un calcul à la volée à chaque consultation pourrait aussi peut-être répondre au besoin.

    Voilà, je suis tout à fait conscient que je n'ai absolument pas répondu à ta question (ou plutôt que je t'ai répondu de trouver la réponse tout seul ;) ) mais j'espère que tu trouveras quand même matière à réflexion dans ce commentaire.

    [1] point acronyme: le DDL (Data Definition Language) permet de modifier la structure d'une base de données. Le DML (Data Manipulation Language) permet de manipuler les données (insertion, modification, suppression, requête)

  • # Modifier le schema dynamiquement

    Posté par . Évalué à 1.

    Bonjour,
    Je me rend compte que j'ai mal posé ma question.
    Le but est bien de faire la manipulation tous les mois dynamiquement.
    Les données calculées seront utilisées tous les mois pour le calcul suivant.

    • [^] # Re: Modifier le schema dynamiquement

      Posté par . Évalué à 2.

      Le but est bien de faire la manipulation tous les mois dynamiquement.
      Les données calculées seront utilisées tous les mois pour le calcul suivant.

      ben tu fais une seule fois la table (id_objet,date, resultat)
      tu la remplie chaque mois avec les resultats precedents, selon la methode de la fenetre glissante decrite plus haut.

      • [^] # Re: Modifier le schema dynamiquement

        Posté par . Évalué à 1.

        C'est bien ce que je pensais, la plupart des applications que j'ai pu voir faisait ainsi, mais je me demandais si c'était pour être le plus générique possible ou s'il y avait d'autres raisons, Sécurité, intégrité des données, performance, développement…

        • [^] # Re: Modifier le schema dynamiquement

          Posté par . Évalué à 4.

          2 questions à ce poser,

          quel pourrait etre l'interet d'avoir 25 tables, qui contiennent toutes (id_objet, mois, données)
          et de devoir, dans ton code, calculer quelle table tu dois interroger en fonction de ce que demande l'utilisateur,
          d'autant plus complexe au changement, disons, d'année, ou tu vas avoir des données à cheval sur deux tables (année en cours, et année predecente)

          alors qu'une seule table contenant les 25 années (25x12 mois) te permet d'avoir un code qui dit juste "va chercher dans la table des resultats"

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.