Partage
  • Partager sur Facebook
  • Partager sur Twitter

SQL Server - GROUP BY 15 min et ORDER BY Date

Comment grouper mes lignes par sequences de 15 min croissantes

Sujet résolu
    26 juillet 2018 à 15:10:21

    Bonjour a tous! :-°

    J'ai une base de données de ce type la:

    ID ScriptName   Time StartDate

    1   Script1Part1    3       20180726 09:00:00

    2   Script1Part2    9       20180726 09:00:03

    3   Script1Part3    1       20180726 09:00:12

    4   Script2Part1    12     20180726 09:15:00

    ...

    Je souhaiterai avoir:

    ID ScriptName Time StartDate

    1  [Script1]        13     20180726 09:00:00

    2  [Script2]        12       20180726 09:15:00

    ...

    Les colonnes Time et StartDate étant les plus importantes

    Je débute juste le SQL, 2 semaines environ, donc ne connaissant que les bases, je suis allé voir sur un Internet (Google est mon amis a ce qui parait). Seulement je trouve des problème similaire mais pas de scenario ressemblant au mien je suis donc un peu perdu o_O

    Voici un bout de la requête que j'ai développe: 

    SELECT 
    
    	/*ID,*/
    	/*ScriptName,*/
    	StartDate,
    	SUM(Time / 1000) AS TimeInSec
    	
    FROM
    
    	table
    
    WHERE
    
    	StartDate >= '20180726 09:00:00.000' AND 
    	StartDate <= '20180726 10:00:00.000'
    
    /*ORDER BY
    
    	StartDate ASC */
    
    GROUP BY
    
    	StartDate, DATEPART(mi, StartDate) / 15

    Le résultat ne me convient pas, d'abord il n'est pas découpe par tranche de 15 min donc le reste ne peut être juste (notamment les sommes de Time) et le résultat n'est pas range par ordre croissant.

    Sans me donner la réponse, pourriez vous me diriger?

    ---

    Petite mise a jour, en faisant quelques recherches

    SELECT 
    
    	--ID,
    	--ScriptName,
    	DATEPART(mi, StartDate) / 15 AS StartDateID,
    	MIN(StartDate) AS StartDate,
    	SUM(Time / 1000) AS TimeInSec
    
    FROM
    
    	table
    
    WHERE
    
    	StartDate >= '20180726 12:00:00.000' AND 
    	StartDate <= '20180726 13:00:00.000'	
    
    --ORDER BY
    
    	--StartDate ASC
    
    GROUP BY
    
    	DATEPART(mi, [StartDate]) / 15

    Donc maintenant il y a juste l'ordre qui me dérange...

    Merci ;)

    -
    Edité par Rymfire 26 juillet 2018 à 16:49:58

    • Partager sur Facebook
    • Partager sur Twitter
    Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
      26 juillet 2018 à 15:46:06

      Bonjour,

      Le problème dans ton énoncé, c'est qu'il peut y avoir des trous plus grand que 15 minutes entre chaque enregistrement ...

      Imaginons les données suivantes :

      ID Script Name StartDate Time
      1 Script1Part1 3 2018-07-26 09:00:00
      2 Script1Part2 9 2018-07-26 09:30:03
      3 Script1Part3 1 2018-07-26 12:00:12
      4 Script2Part1 12 2018-07-26 12:07:00

      Que veux-tu comme résultat avec celles-ci ?

      -
      Edité par Benzouye 26 juillet 2018 à 16:00:26

      • Partager sur Facebook
      • Partager sur Twitter
      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
        26 juillet 2018 à 16:15:18

        Benzouye a écrit:

        Bonjour,

        Le problème dans ton énoncé, c'est qu'il peut y avoir des trous plus grand que 15 minutes entre chaque enregistrement ...

        Imaginons les données suivantes :

        ID Script Name StartDate Time
        1 Script1Part1 3 2018-07-26 09:00:00
        2 Script1Part2 9 2018-07-26 09:30:03
        3 Script1Part3 1 2018-07-26 12:00:12
        4 Script2Part1 12 2018-07-26 12:07:00

        Que veux-tu comme résultat avec celles-ci ?

        -
        Edité par Benzouye il y a 8 minutes

        En fait les différentes partie du script se suivent et ne peuvent pas excéder 15 min au total. Il y a un 'Time-out' sur chaque partie de script lance pour ne pas avoir a traiter ce cas la.

        Par contre il y a 4 attributs a ma table:

        • ID: clé primaire
        • ScriptName: le nom du script lance (au total toute les parties pour un script ne peuvent dépasser 15 min)
        • StartDate: la date du démarrage du script
        • Time: la durée du script

        Ca répond a ta question...?

        -
        Edité par Rymfire 26 juillet 2018 à 16:19:22

        • Partager sur Facebook
        • Partager sur Twitter
        Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
          26 juillet 2018 à 17:01:34

          Si je regarde ton premier message, on dirait que tu veux juste obtenir le premier enregistrement pour chaque script ...

          Ce que je ferai simplement avec :

          SELECT
              ScriptName,
              MIN( CONCAT( StartDate, ' ', Time ) ) AS StartDate
          FROM table
          WHERE
              StartDate >= '20180726 12:00:00.000'
          	AND StartDate <= '20180726 13:00:00.000'
          GROUP BY ScriptName
          ORDER BY StartDate

          Mais il y a quelque chose que je ne comprends pas dans ton histoire de quart d'heure ...

          • Partager sur Facebook
          • Partager sur Twitter
          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
            26 juillet 2018 à 17:13:50

            Benzouye a écrit:

            Mais il y a quelque chose que je ne comprends pas dans ton histoire de quart d'heure ...

            Imaginons que je dois lancer mon script chaque 15 min, la partie 1 s'exécute, puis la partie 2, puis la 3, et ainsi de suite jusque la dernière. Tous cela est limite par un time-out pour ne pas dépasser les 15 min. On a donc 1 enregistrement pour chaque partie de mon script.

            Je souhaiterai grouper toute mes partie de script en un seul pour avoir le temps total de mon script exécuté et ce, chaque 15 min; donc 1 enregistrement correspond a un script.

            Donc pour chaque enregistrement (après changement), je connais la date de la première partie de mon script (date de démarrage du script logiquement) et la durée totale de mon script (somme des durées de mes parties de script). Tous ca, dans l'ordre croissant.

            • Partager sur Facebook
            • Partager sur Twitter
            Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
              26 juillet 2018 à 17:37:10

              Je reviens donc sur ma première remarque :

              Benzouye a écrit:

              Le problème dans ton énoncé, c'est qu'il peut y avoir des trous plus grand que 15 minutes entre chaque enregistrement ...

              En changeant un peu pour dire qu'il est ici impossible de déterminer dans quelle exécution d'un même script l'on se trouve ...

              Je pense que c'est la façon de stocker l'information qui n'est pas bonne pour obtenir ce que tu souhaites ...

              Je verrais plutôt le trucs en 3 tables :

              • script ( id [pk], nom, etc. ) table pour stocker les différents scripts possibles
              • partie ( id [pk], id_script [fk], nom, ordre, etc. ) table pour stocker chaque partie de chaque script
              • execution ( id [pk], id_script [fk], start_time, end_time ) table pour stocker chaque lancement de script avec début et fin

              Les colonnes début et fin seront des DATETIME. Quand tu lances l'exécution d'un script (sa première partie), tu crées un enregistrement dans la table exécution avec sa date/heure de début et sans date/heure de fin (ce qui te permet au passage de connaître les scripts en cours d'exécution, ceux qui n'ont pas de date/heure de fin).

              Tu lances chaque partie du script en faisant référence à l'exécution concernée (avec l'id), et quand la dernière partie se termine tu viens mettre à jour l'enregistrement exécution pour mettre sa date/heure de fin

              Si tu veux entrer dans le détail par partie, il te faudrait une quatrième table :

              • script ( id [pk], nom, etc. ) table pour stocker les différents scripts possibles
              • partie ( id [pk], id_script [fk], nom, ordre, etc. ) table pour stocker chaque partie de chaque script
              • execution_script ( id [pk], id_script [fk], creation ) table pour stocker chaque lancement de script avec début
              • execution_partie ( id [pk], id_execution [fk], id_partie [fk], start_time, end_time )

              Dans ce modèle pour chaque partie que tu lances tu crées un enregistrement dans la table execution_partie avec sa  date/heure de début. En fin de partie tu mets à jour la date/heure de fin ... tu as alors une gestion fine, et ce par exécution ...

              • Partager sur Facebook
              • Partager sur Twitter
              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                27 juillet 2018 à 9:46:22

                Benzouye a écrit:

                En changeant un peu pour dire qu'il est ici impossible de déterminer dans quelle exécution d'un même script l'on se trouve ...

                Je pense que c'est la façon de stocker l'information qui n'est pas bonne pour obtenir ce que tu souhaites ...

                Je verrais plutôt le trucs en 3 tables :

                • script ( id [pk], nom, etc. ) table pour stocker les différents scripts possibles
                • partie ( id [pk], id_script [fk], nom, ordre, etc. ) table pour stocker chaque partie de chaque script
                • execution ( id [pk], id_script [fk], start_time, end_time ) table pour stocker chaque lancement de script avec début et fin

                Les colonnes début et fin seront des DATETIME. Quand tu lances l'exécution d'un script (sa première partie), tu crées un enregistrement dans la table exécution avec sa date/heure de début et sans date/heure de fin (ce qui te permet au passage de connaître les scripts en cours d'exécution, ceux qui n'ont pas de date/heure de fin).

                Je suis tout a fait d'accord avec toi, il y a un quelque chose a cette table... Cependant je ne peut revoir la table car ce n'est pas ma base de donnée. On me demande juste de faire avec malgré les défauts de la base. :'( Du coup, faute d'avoir un attribut indiquant les groupes de partie de script du même script, je sais que chaque script est exécute toutes les 15 min donc je dois séparer par tranche de 15 min...

                • Partager sur Facebook
                • Partager sur Twitter
                Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
                  27 juillet 2018 à 10:33:40

                  Rymfire a écrit:

                  je sais que chaque script est exécute toutes les 15 min donc je dois séparer par tranche de 15 min

                  Si tu n'as aucun moyen de déterminer un groupe alors tu ne peux pas l'inventer ... Ton critère de tranche de 15 minutes n'est pas valable car tu peux chevaucher sur deux exécutions du même script car tu ne peux pas fiablement définir ces exécutions ...

                  As-tu au moins un moyen de déterminer quel enregistrement correspond à la première partie de chaque exécution ? Au vu des exemple il ne me semble pas ...

                  -
                  Edité par Benzouye 27 juillet 2018 à 10:34:06

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                    27 juillet 2018 à 11:54:46

                    Benzouye a écrit:

                    Si tu n'as aucun moyen de déterminer un groupe alors tu ne peux pas l'inventer... Ton critère de tranche de 15 minutes n'est pas valable car tu peux chevaucher sur deux exécutions du même script car tu ne peux pas fiablement définir ces exécutions ...

                    As-tu au moins un moyen de déterminer quel enregistrement correspond à la première partie de chaque exécution ? Au vu des exemple il ne me semble pas ...

                    Je viens de comprendre... Effectivement mon raisonnement est mauvais... Je vais précéder autrement.

                    Merci pour ton aide! :euh:

                    PS: Si ca peut servir a quelqu'un, en cherchant un peu, j'en suis arrive a la:

                    SELECT 
                    
                    	DATEPART(mi, StartDate) / 15 AS StartID,
                    	MIN(StartDate) AS ScriptStartDate,
                    	SUM(Time / 1000) AS TimeInSec
                    
                    FROM
                    
                    	table
                    
                    WHERE
                    
                    	StartDate >= '20180726 12:00:00.000' AND 
                    	StartDate <= '20180726 13:00:00.000'
                    
                    GROUP BY
                    
                    	DATEPART(mi, StartDate) / 15
                    
                    ORDER BY
                    
                    	StartID



                    -
                    Edité par Rymfire 27 juillet 2018 à 11:55:56

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
                      27 juillet 2018 à 12:06:44

                      Je ne comprends pas en quoi cette requête est une solution ... Si la première partie du script a démarré à 11:57 alors il te manquera le temps d'exécution de cette partie ... le résultat est faussé ... de plus la requête t'impose de ne regarder qu'une seule heure ...

                      Rymfire a écrit:

                      Je souhaiterai grouper toute mes partie de script en un seul pour avoir le temps total de mon script exécuté

                      N'as-tu pas un moyen d'identifier qu'une ligne concerne la première partie d'un script ? Un facteur commun dans le name par exemple ?

                      Peux-tu nous donner un exemple "réel" de données (quelques lignes) ?

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                        27 juillet 2018 à 14:39:51

                        Ce n'est pas une solution, loin de la... Quand je disais que chaque script tourne toute les 15 min ca veut dire que le premier est a 00:00:xx.xxx, le second a 00:15:xx.xxx, le troisième a 00:30:xx.xxx, [...], le cinquième a 01:00:xx.xxx et ainsi de suite...

                        En gros voila ce que ca devrait donner avec des +/- vrais données:

                        ID            ScriptName                        StartDate                           TimeInSec

                        1723653  Script-1-Login                       2018-07-26 22:00:09.733   13
                        1723658  Script-2-OpenExcel                2018-07-26 22:00:35.010   26
                        1723670  Script-3-OpenWord                2018-07-26 22:01:14.113   34
                        1723672  Script-4-OpenPowerPoint       2018-07-26 22:01:58.957   26
                        1723676  Script-5-OpenOutlook            2018-07-26 22:02:38.133   19
                        1723680  Script-6-CloseAll                   2018-07-26 22:03:07.940   34
                        1723683  Script-99-Logoff                    2018-07-26 22:03:52.953   4
                        1723750  Script-1-Login                       2018-07-26 22:15:07.750   13
                        1723754  Script-2-OpenExcel                2018-07-26 22:15:33.000   26
                        1723756  Script-3-OpenWord                2018-07-26 22:16:11.970   33
                        1723766  Script-4-OpenPowerPoint        2018-07-26 22:16:57.007   26
                        1723768  Script-5-OpenOutlook             2018-07-26 22:17:36.177   19
                        1723776  Script-6-CloseAll                    2018-07-26 22:18:05.963   33
                        1723782  Script-99-Logoff                    2018-07-26 22:18:50.893    4

                        [etc]

                        -
                        Edité par Rymfire 27 juillet 2018 à 14:47:55

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
                          27 juillet 2018 à 15:27:18

                          Rymfire a écrit:

                          Script-1-Login

                          Si l'on prend cet exemple de ScriptName, la structure est-elle toujours la même ? à savoir :

                          le mot "script" + un tiret + le numéro de la partie du script + un tiret + l'intitulé de la partie

                          Cela pour reprendre ma question :

                          Benzouye a écrit:

                          N'as-tu pas un moyen d'identifier qu'une ligne concerne la première partie d'un script ? Un facteur commun dans le name par exemple ?

                          Si oui, quel serait-il ?

                          Un exemple pour étayer ma réflexion :

                          SELECT
                          	T1.ID,
                          	T1.ScriptName,
                          	T1.StartDate,
                          	SUM(T2.TimeInSec) AS TotalTimeInSec
                          FROM
                          	table T1
                          		INNER JOIN table T2
                          			ON DATEADD( minute, 15, T1.StartDate ) > T2.StartDate
                          			AND T1.StartDate =< T2.StartDate
                          WHERE
                          	T1.ScriptName LIKE '%-1-%'
                          	AND T1.StartDate >= '20180726 00:00:00.000'
                          	AND T1.StartDate < '20180727 00:00:00.000'
                          GROUP BY
                          	T1.ID,
                          	T1.ScriptName,
                          	T1.StartDate

                          L'idée c'est de faire une auto jointure pour retrouver les éléments dans un intervalle de 15 minutes à partir de l'élément contenant dans son nom "-1-", qui serait l'élément de départ de chaque script ...

                          Pour tester cela, ajoute une borne sur la date pour éviter de traiter trop de données ...

                          -
                          Edité par Benzouye 27 juillet 2018 à 15:28:40

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                            27 juillet 2018 à 17:23:00

                            Benzouye a écrit:

                            FROM
                            	table T1
                            		INNER JOIN table T2
                            			ON DATEADD( minute, 15, T1.StartDate ) > T2.StartDate
                            			AND T1.StartDate =< T2.StartDate
                            GROUP BY
                            	T1.ID,
                            	T1.ScriptName,
                            	T1.StartDate

                            L'idée c'est de faire une auto jointure pour retrouver les éléments dans un intervalle de 15 minutes à partir de l'élément contenant dans son nom "-1-", qui serait l'élément de départ de chaque script...

                            Je ne comprends pas tout a fais ce que représente le 'T2.StartDate', vous pouvez m'expliquer?

                            Je ne comprend pas non plus pourquoi grouper par ces éléments la...:(

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
                              27 juillet 2018 à 17:56:37

                              T1 et T2 sont les alias pour nommer la même table avec des conditions de sélection différentes.

                              T1 va retourner la liste des enregistrements contenant "-1-" dans leur ScriptName.

                              T2 va retourner pour chaque enregistrement de T1 les enregistrements des 15 minutes suivantes.

                              Pour comprendre comment cela fonctionne, il faut décomposer.

                              Choisissons un ID de la table qui correspond à la première partie d'un script. Par exemple 1723653 selon tes données plus haut.

                              SELECT
                              	T1.ID,
                              	T1.ScriptName,
                              	T1.StartDate,
                              	T2.ID,
                              	T2.ScriptName,
                              	T2.TimeInSec
                              FROM
                              	table T1
                              		INNER JOIN table T2
                              			ON DATEADD( minute, 15, T1.StartDate ) > T2.StartDate
                              			AND T1.StartDate =< T2.StartDate
                              WHERE T1.ID = 1723653

                              Cette requête devrait te retourner tous les enregistrements dans le quart d'heure qui a suivi l'exécution du script d'ID 1723653.

                              Selon tes dires ces enregistrements seront tous du même script ...

                              Du coup tu peux faire la somme des temps d'exécution :

                              SELECT
                              	T1.ID,
                              	T1.ScriptName,
                              	T1.StartDate,
                              	SUM( T2.TimeInSec ) AS TotalTimeInSec
                              FROM
                              	table T1
                              		INNER JOIN table T2
                              			ON DATEADD( minute, 15, T1.StartDate ) > T2.StartDate
                              			AND T1.StartDate =< T2.StartDate
                              WHERE T1.ID = 1723653
                              GROUP BY
                              	T1.ID,
                              	T1.ScriptName,
                              	T1.StartDate

                              Là c'est donc la somme des temps d'exécution des enregistrements dans le quart qui a suivi le script d'ID 1723653.

                              Donc si la condition suivante :

                              T1.ScriptName LIKE '%-1-%'

                              Est suffisante pour isoler toutes les premières parties d'exécution d'un script, et qu'aucun script ne peut s'intercaler avec un autre dans le même quart d'heure, alors ma requête devrait fonctionner ...

                              D'où mon éternelle question :

                              Benzouye a écrit:

                              N'as-tu pas un moyen d'identifier qu'une ligne concerne la première partie d'un script ? Un facteur commun dans le name par exemple ?

                              Et ce facteur est-il "ScriptName contient -1-" ?

                              -
                              Edité par Benzouye 27 juillet 2018 à 17:58:18

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                                30 juillet 2018 à 10:06:03

                                Benzouye a écrit:

                                D'où mon éternelle question :

                                Benzouye a écrit:

                                N'as-tu pas un moyen d'identifier qu'une ligne concerne la première partie d'un script ? Un facteur commun dans le name par exemple ?

                                Et ce facteur est-il "ScriptName contient -1-" ?

                                Oui, la première partie du script seras toujours identifiable par un "-1-". En ce qui concerne la requête que tu m'as écris, je vais regarder de mon cote mais elle devrait constituer une bonne base pour la suite de mon projet. Je te tiens au courant si quelque chose va pas mais ça devrai aller :D MERCI!
                                • Partager sur Facebook
                                • Partager sur Twitter
                                Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
                                  31 juillet 2018 à 10:57:18

                                  Rymfire a écrit:

                                  Je te tiens au courant si quelque chose va pas mais ça devrai aller :D MERCI!


                                  Je te remercie pour ton aide Benzouye, j'ai trouve un moyen de faire ce que je voulais faire sans trop rendre la chose complique.

                                  A une prochaine fois! :soleil:

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.
                                    31 juillet 2018 à 11:02:20

                                    Cool :)

                                    Par contre je pense que ce n'est pas une bonne solution que de maintenir un schéma de base de données incorrect. Essaye peut-être de pousser un peu pour que chaque exécution soit numérotée en base ...

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                                      1 août 2018 à 10:55:56

                                      Benzouye a écrit:

                                      Par contre je pense que ce n'est pas une bonne solution que de maintenir un schéma de base de données incorrect. Essaye peut-être de pousser un peu pour que chaque exécution soit numérotée en base ...


                                      Je suis tout a fait d'accord, la base de donnée de mon employeur n'est pas super bien construite, mais ça m’étonnerai qu'ils écoutent un stagiaire leur faire des réflexions... :-° Je vais au moins essayer de leur faire numéroter les parties de script ds un attribut (sachant que celui ci existe mais n'est pas utilise) o_O
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.

                                      SQL Server - GROUP BY 15 min et ORDER BY Date

                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                      • Editeur
                                      • Markdown