Partage
  • Partager sur Facebook
  • Partager sur Twitter

[MySQL] Insert en fonction du dernier rang

    1 mars 2018 à 18:38:41

    Bonjour/soir à tou.te.s =)

    Bien que je passe sur OC depuis un certains temps pour y puiser des informations, c'est mon tout premier post, n'hésitez donc pas à me signaler quoi que ce soit que je pourrais faire de travers :$

    Pour résumer, je travaille depuis peu pour une radio associative, et nous souhaiterions mettre en place sur notre site un outil permettant aux auditeurs de retrouver un titre en fonction de l'heure à laquelle ils l'ont entendu.

    Mais avant de bosser sur l’outil, j'aimerais avoir une BdD propre a exploiter.

    Notre infrastructure étant 'particulière', je dois exploiter un fichier .txt mis à jour chaque minute avec le titre de la musique qui passe à cet instant ; je n'ai pas d'autre source possible.

    Le problème, c'est qu'avec le code que nous avons mis en place, la base se remplie chaque minutes, par exemple :

    18h01 artiste A - chanson A

    18h02 artiste A - chanson A

    18h03 artiste B - chanson B

    18h04 artiste B - chanson B

    18h05 artiste B - chanson B

    18h06 artiste C - chanson C

    Là ou nous voudrions :

    18h01 artiste A - chanson A

    18h03 artiste B - chanson B

    18h06 artiste C - chanson C

    Le script actuel est :



    var=`cat /home/prod/scripts/encours.txt`

    echo "INSERT IGNORE INTO wp_playlist (date,titre) VALUES (NOW(), '$var');" | [info de connexion à la BdD]

    Quelqu'un aurait il une idée pour que l'INSERT ne se fasse que si le dernier rang de la colonne 'titre' n'est pas dèjà présent en dernier rang ?

    J’espère être clair dans mon propos, n'hésitez pas pour tout renseignement complémentaire ; et d'avance merci à quiconque prendra un peu de son temps pour nous aider :)

    Cordialement,

    Pierre

    • Partager sur Facebook
    • Partager sur Twitter
      1 mars 2018 à 22:21:51

      Salut,

      Le plus simple serait de vérifier si le même titre n'a pas déjà été enregistré dans la base il y a moins de x minutes :

      SELECT titre FROM wp_playlist 
      WHERE TIMESTAMPDIFF(MINUTE, NOW(), date) <= 10
      AND titre = '$var'

      Et si et seulement si la requête ne renvoie rien, on fait l'insertion.

      • Partager sur Facebook
      • Partager sur Twitter
      Contrôleur programmeur des finances publiques depuis le 01/10/18
        2 mars 2018 à 9:19:42

        Bonjour,

        Est-il possible qu'un même titre soit diffuser plusieurs fois à la même date ?

        Car je proposerais plutôt de modifier la table et de séparer date et heure, et de mettre une contrainte UNIQUE ( date, titre ), du coup le INSERT IGNORE fonctionnerait comme attendu ...

        • Partager sur Facebook
        • Partager sur Twitter
        Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
          2 mars 2018 à 11:29:31

          Tout d'abord merci pour votre temps et vos idées.

          @Benzouye : une partie de notre playlist est en 'rotation lourde', et certains titres peuvent passer 2/3 fois sur une même journée, du coup seul le premier passage serait pris en compte si j'ai bien compris.

          @_Florent_ : je me penche sur votre idée et vous tiens informé :)

          • Partager sur Facebook
          • Partager sur Twitter
            2 mars 2018 à 12:04:43

            PierreRca a écrit:

            une partie de notre playlist est en 'rotation lourde', et certains titres peuvent passer 2/3 fois sur une même journée, du coup seul le premier passage serait pris en compte si j'ai bien compris.

            Oui c'est bien ça ... Par contre tu peux imaginer un système plus précis, un peu plus comme propose Florent. Je m'explique ...

            Imaginons le modèle suivant :

            • titre ( id_titre [pk], libelle [unique] )
            • programmation ( date_prog [pk], id_titre [pk][fk] )
            • import ( id_moment [pk], date_prog [fk], heure_prog, id_titre [fk] )

            Derrière tu peux mettre une logique programmée :

            • tu essayes de créer le titre. Soit tu récupères l'id existant soit tu récupères l'id créé
            • tu essayes de créer la prog (INSERT IGNORE)
            • tu crées l'import

            De cette manière, tu peux dire quel titre passe à quel moment, mais aussi quand il a déjà été diffusé ...

            • Partager sur Facebook
            • Partager sur Twitter
            Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
              19 mars 2018 à 16:50:04

              Bonjour :)

              Désolé pour le temps de réponse, j'ai pas mal de choses à gérer...

              J'ai déduis ça à partir de vos propos, je le teste dés que je peux et je vous tiendrai informé =)

              var=`cat /home/prod/scripts/encours.txt`
              
              $result = mysql_query("SELECT titre FROM wp_playlist WHERE TIMESTAMPDIFF(MINUTE, NOW(), date) <= 10 AND titre = '$var' ;" |[données de connexion])
              
              $rowcount=mysql_num_rows($result);
              
              if($rowcount<1){echo "INSERT IGNORE INTO wp_playlist (date,titre) VALUES (NOW(), '$var');" |[données de connexion]}



              • Partager sur Facebook
              • Partager sur Twitter
                19 mars 2018 à 17:03:13

                Par ailleurs je ne peux que t'encourager d'oublier les fonctions mysql_* (obsolètes et peu sécurisées) au profit des fonctions mysqli_* voire de la classe PDO (cf. ma signature).
                • Partager sur Facebook
                • Partager sur Twitter
                Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                  20 mars 2018 à 12:04:04

                  Il faut éviter les algoritme en deux étapes. Ici, récupérer avec un select pour n’insérer que s'il n'est pas présent. Si par malheurs ton script se déclenche plus d'une fois au même moment (bug, mauvaise configuration etc...) tu va avoir un problème de concurrence, et ta valeur va être inscrite plusieurs fois.

                  Pour éviter ça, on peut utiliser les transactions (mais c'est assez lourd, et il est déconseillé de déporter les transaction dans le programme qui exploite la BDD). Ou utiliser un INSERT SELECT.

                  INSERT INTO wp_playlist (date,titre) SELECT NOW(), '$var' WHERE NOT EXISTS (SELECT * FROM wp_playlist WHERE date = NOW() AND titre = '$var') 

                  Moi je mettrais simplement le champ date au format TIMESTAMP, permettant d'avoir à la fois la date et l'heure dans le même champ.

                  Par contre, si on veut bien faire les choses, il faut deux timestamp : un pour le début et l'autre pour la fin de la diffusion du titre. C'est d'autant plus vrai que la contrainte pour l'insertion doit en fait vérifier que le même titre n'est pas déjà en cours de lecture (même s'il n'ont pas forcément le même timestamp de début)

                  Ce qui donnerait avec l modèle suivant programation(id_titre, start, end)

                  INSERT INTO playlist (id_titre, start, end)
                  SELECT titre.id NOW(), NULL
                  FROM titre
                  WHERE NOT EXISTS (SELECT * FROM playlist INNER JOIN titre ON titre.id = id_titre WHERE titre.name = '$var' AND end IS NULL  );

                  Il faut ensuite rajouter un trigger, qui doit se déclencher à chaque insertion, pour mettre à jour la date de fin (ici avec la syntaxe de PostgreSQL, je ne connais pas celle de MySQL)

                  CREATE RULE R_I_PLAYLIST AS
                    ON INSERT
                    TO playlist
                    DO ALSO (
                      UPDATE playlist SET end = NOW() WHERE end IS NULL AND id_titre != NEW.id_titre;
                    );




                  • Partager sur Facebook
                  • Partager sur Twitter
                    20 mars 2018 à 17:27:27

                    Bon bah ce que j'ai fait ne fonctionne pas...

                    J'ai oublié de préciser que je travaille sous Linux et que mon script est lancé via le CRON.

                    @Benzouye : j'ai cherché dans les menus que vous pointez dans votre signature, mais je n'ai rien trouvé sur les msqli_, du coup j'ai lu ça : http://php.net/manual/fr/mysqli-stmt.num-rows.php

                    Je suis complètement perdu là, entre le bash, mysql et php...

                    "Je vais m'arracher ce qu'il me reste de cheveux et je reviens."

                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 mars 2018 à 17:44:07

                      Représentes-nous ton code et la structure de ta base de données ... Je n'ai personnellement aucune idée de où tu en es ...
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                        22 mars 2018 à 11:08:54

                        Bonjour =)

                        Concernant la BdD, elle peut être refaite, mais l'idéal serait d'avoir deux données :

                        - 'titre de la chanson - groupe', ce qui est récupéré sur le .txt mis à jour chaque minute par le CRON

                        - 'date et heure de passage'

                        En me basant sur ce que mon prédecesseur avait fait et sur mes recherches, mon code actuel est :

                        #!/bin/bash
                        
                        var=`cat /home/prod/scripts/encours.txt`
                        
                        $result = mysql_query("SELECT titre FROM wp_playlist WHERE TIMESTAMPDIFF(MINUTE, NOW(), date) <= 10 AND titre = '$var' ;" |/usr/bin/mysql -A [login/serveur/mdp/table])
                        
                        $rowcount=mysql_num_rows($result);
                        
                        if($rowcount<1){echo "INSERT IGNORE INTO wp_playlist (date,titre) VALUES (NOW(), '$var');" |/usr/bin/mysql -A [login/serveur/mdp/table]}


                        Le script est lancé par CRON chaque minute.

                        -
                        Edité par PierreRca 22 mars 2018 à 11:10:00

                        • Partager sur Facebook
                        • Partager sur Twitter
                          22 mars 2018 à 14:18:10

                          En considérant que le fichier ne contient qu'une seule ligne avec le titre, et sans toucher à ta base.

                          On oublie mysql_* au profit de PDO, et on oublie le bash au profit de fopen ;)

                          Je crée également un fichier log.txt pour stocker les erreurs au cas où ...

                          <?php
                          	try {
                          		// On ouvre le fichier en lecture
                          		$fichier = fopen( 'encours.txt', 'r' );
                          		// On récupère la première ligne
                          		$encours = fgets( $fichier );
                          		// On ferme le fichier
                          		fclose( $fichier );
                          		
                          		// Connexion MySQL
                          		$options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
                          		$options[PDO::ATTR_DEFAULT_FETCH_MODE] = PDO::FETCH_OBJ;
                          		$bdd = new PDO( 'mysql:host=localhost;dbname=mvc;', 'root', '', $options );
                          		
                          		// Vérifies si le titre existe depuis 5 minutes (au cas où)
                          		$requete = $bdd->prepare( '
                          			SELECT titre
                          			FROM wp_plaaylist
                          			WHERE
                          				titre = ?
                          				AND `date` > NOW()-INTERVAL 5 MINUTE;'
                          		);
                          		$requete->execute( array( $encours ) );
                          		
                          		// Si le titre n'existe pas on le crée
                          		if( !$requete->fetchColumn() ) {
                          			$requete = $bdd->prepare( '
                          				INSERT INTO wp_playlist ( titre, `date` )
                          				VALUES ( ?, NOW() );'
                          			);
                          			$requete->execute( array( $encours ) );
                          		}
                          	}
                          	catch(Exception $e) {
                          		// On crée ou on ouvre le fichier de log
                          		$fichier = fopen( 'log.txt', 'a+' );
                          		// On stocke l'erreur
                          		fputs( $fichier, date('Y-m-d H:i').' - '.$e->getMessage()."\n" );
                          		// On ferme le fichier
                          		fclose( $fichier );
                          	}
                          ?>

                          -
                          Edité par Benzouye 22 mars 2018 à 14:19:02

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                            22 mars 2018 à 18:09:00

                            Tout d'abord, encore merci pour votre temps.

                            En effet le .txt ne contient qu'une ligne, par contre je ne comprends pas comment le 'fopen' le localise. (en sachant qu'il est dans le même dossier que le script)

                            De la même manière, où serait créé le fichier de log ?

                            Au niveau du bash, j'ai cru comprendre qu'il fallait lui indiquer où trouver php, par exemple '/usr/bin/php', est ce toujours nécessaire ?

                            -
                            Edité par PierreRca 22 mars 2018 à 18:10:21

                            • Partager sur Facebook
                            • Partager sur Twitter
                              23 mars 2018 à 9:00:55

                              Pour accéder au fichier demandé, la commande fopen utilise le chemin spécifié. Si aucun chemin, alors c'est depuis la position du fichier PHP que sera recherché le fichier. Si encours.txt est dans le même répertoire que celui du fichier PHP exécuté, alors pas plus à renseigner ...

                              Idem pour le fichier de log, il sera créé et recherché dans le même répertoire que celui du fichier PHP exécuté.

                              Il faut donc s'assurer que les droits d'accès au répertoire en question sont suffisant (604 par exemple).

                              Au niveau du bash, si les liens vers le répertoire PHP sont créés sur ton serveur, alors l'exécution devrait fonctionner normalement. CRON va demander l'exécution d'un fichier PHP et le serveur saura que c'est à exécuter avec PHP ... normalement ... après je ne suis pas du tout expert en la matière.

                              Teste déjà le code donné manuellement (via son URL), puis teste ensuite via crontab ;)

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

                                Bonjour,

                                C'est clair pour les positions, merci :)

                                Je ne vois pas comment je pourrais tester le code car le .txt et le script ne sont pas sur le serveur mais sur un PC dans nos locaux.

                                Du coup je tente par le CRON (après avoir entré les infos BdD ;) ), mais ça ne prend pas.

                                Mon CRON est :

                                */1 * * * * /usr/bin/php -f /home/prod/scripts/titragebdd.php

                                Je ferai quelques recherches pendant le week-end, je finirai bien par trouver ^^

                                Bon week-end à vous :)

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  24 mars 2018 à 11:26:01

                                  PierreRca a écrit:

                                  le .txt et le script ne sont pas sur le serveur mais sur un PC dans nos locaux

                                  Euh le CRON le PHP et le txt doivent se trouver sur le serveur où se trouve MySQL et PHP ...

                                  Si ton PC local n'a pas de serveur PHP il ne pourra exécuter le script PHP ...

                                  Peux-tu détailler un peu le fonctionnement ? Qui génère le fichier txt ? Où le dépose-t-il ?

                                  Où se trouve le serveur avec le cron et PHP ?

                                  Où se trouve le serveur web avec lequel tu veux afficher les données de la base de données ?

                                  • 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 mars 2018 à 11:35:15

                                    Bonjour :)

                                    Le PC 'local1' qui gère le flux RDS de la radio lance chaque minute un script bash qui met à jour le .txt sur une autre machine 'local2' à partir du RDS, je n'ai pas d'autre possibilité.

                                    Le 'local2' sur lequel se trouve le .txt (dans le même dossier que le script)  s'occupe du CRON. J'y ai installé Php.

                                    La BdD est sur un serveur externalisé.

                                    Les données seront exploitées sur le site se trouvant sur le même serveur.

                                    Avant que j'y touche ça fonctionnait, mal, la base se remplissant incorrectement (cf. premier message) ; c'est pour ça que je cherchais une requête plus élaborée.

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      26 mars 2018 à 13:32:01

                                      Si tu exécutes manuellement le fichier PHP que se passe-t-il ?

                                      Depuis le poste local2 ...

                                      -
                                      Edité par Benzouye 26 mars 2018 à 13:32:53

                                      • 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 mars 2018 à 16:04:00

                                        Bonjour :)

                                        Le retour de l’exécution manuelle :

                                        PHP Warning:  fopen(encours.txt): failed to open stream: No such file or directory in /home/prod/scripts/titragebdd.php on line 4
                                        PHP Warning:  fgets() expects parameter 1 to be resource, boolean given in /home/prod/scripts/titragebdd.php on line 6
                                        PHP Warning:  fclose() expects parameter 1 to be resource, boolean given in /home/prod/scripts/titragebdd.php on line 8
                                        



                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          28 mars 2018 à 10:27:29

                                          Il ne trouve pas le fichier encours.txt dans le répertoire ... Du coup rien ne se passe ensuite ...

                                          Assure-toi que le fichier encours.txt soit présent dans le répertoire où se trouve le fichier PHP ... et qu'il contienne bien une ligne également ...

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

                                            Bonjour :)

                                            Je viens de refaire un test en spécifiant l’accès à encours.txt -alors qu'il est dans le même dossier (et contient une ligne)- et là le script s'est exécuté sans rien envoyer en retour, ni mettre la base à jour.

                                            Je devrais avoir du temps pour me pencher dessus aujourd'hui et demain.

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              5 avril 2018 à 16:02:40

                                              PierreRca a écrit:

                                              en spécifiant l’accès à encours.txt

                                              C'est à dire ? Quel est le code ?

                                              PierreRca a écrit:

                                              le script s'est exécuté sans rien envoyer en retour, ni mettre la base à jour

                                              Et pas de fichier log.txt créé ?
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                                                6 avril 2018 à 10:59:38

                                                Bonjour,

                                                Benzouye a écrit:

                                                C'est à dire ? Quel est le code ?

                                                Je me suis mal exprimé : j'ai juste spécifié le chemin d'accès au fichier /home/prod/scripts/encours.txt

                                                Benzouye a écrit:

                                                Et pas de fichier log.txt créé ?

                                                Si, je ne l'avais pas vu au départ car il a été créé dans /home/prod/

                                                Il retourne :

                                                2018-04-05 14:19 - could not find drive
                                                2018-04-05 14:20 - could not find drive




                                                -
                                                Edité par PierreRca 6 avril 2018 à 11:00:30

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  6 avril 2018 à 13:37:38

                                                  Donc c'est que ta chaîne de connexion ( new PDO( ... ) ) appelle un driver non disponible sur ton PHP ... Vérifies que le driver MySQL est disponible ...
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                                                    6 avril 2018 à 14:50:32

                                                    mysql -V renvoit :

                                                    mysql  Ver 14.14 Distrib 5.5.58, for debian-linux-gnu (i686) using readline 6.3

                                                    Mon erreur pourrait elle venir de ma façon de me connecter ?

                                                     $bdd = new PDO( 'mysql:host=hébergeur.net;dbname=nomdelabase;', 'id', 'mdp', $options );


                                                    Edit:

                                                    Dans le doute j'ai quand même relancé un sudo apt-get install php5-mysql et un sudo apt-get install pdo-mysql qui lui retourne :

                                                    Lecture des listes de paquets... Fait
                                                    Construction de l'arbre des dépendances       
                                                    Lecture des informations d'état... Fait
                                                    E: Impossible de trouver le paquet pdo-mysql

                                                    En relançant le titragebdd.php le résultat en log est :

                                                    2018-04-06 15:26 - SQLSTATE[HY000] [2005] Unknown MySQL server host 'hébergeur.net' (25)

                                                    re-edit: j'ai trouvé l'erreur de connexion, maintenant ça donne :

                                                    2018-04-06 15:50 - SQLSTATE[42000] [1044] Access denied for user 'xxxxxxx'@'%' to database 'xxxxxxxxxxxxxxx'

                                                    re-re-edit : avec des données corrects ça fonctionne ! Le script lancé manuellement a enregistré dans la BdD !

                                                    <3 Benzouye

                                                    J'ai plus qu'a automatiser le bidule ^^

                                                    -
                                                    Edité par PierreRca 6 avril 2018 à 16:03:39

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      6 avril 2018 à 22:38:14

                                                      Ah bah tu vois quand tu veux ;)
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL

                                                      [MySQL] Insert en fonction du dernier rang

                                                      × 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