Enregistrement suivant

Résolu
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 - 27 juin 2008 à 23:06
nicomilville Messages postés 3472 Date d'inscription lundi 16 juillet 2007 Statut Membre Dernière intervention 28 février 2014 - 29 juin 2008 à 09:17
Je souhaite connaitre l'enregistrement suivant à partir d'un enregistrement donné selon un ordre chronologique. Le problème parait être simple, mais en réalité les solutions que l'on serait tenté d'utiliser en premier lieu sont incorrectes.

Mettons que j'aie une table d'évènements structurée de la façon suivante :

CREATE TABLE "event" (
  "cle" int(10) unsigned NOT NULL,
  "date" datetime NOT NULL default '0000-00-00 00:00:00',
  "texte" text NOT NULL,
  PRIMARY KEY  ("cle"),
) AUTO_INCREMENT= 1 ;

Pour trouver un enregistrement suivant un autre je pourrais utiliser une des deux requêtes suivantes (ou une_cle et une_date sont respectivement la clé et la date de l'enregistrement courant) :

SELECT * FROM event WHERE cle> une_cleLIMIT 0, 1
SELECT * FROM event WHERE date> une_dateLIMIT 0, 1

Le problème de ces requetes, ce sont les conditions utilisées. Utiliser la clé dans la condition n'est pas valable dans le cas où les dates changent, car dans ce cas, l'ordre des clés ne correspond pas à l'ordre chronologique. Utiliser la date, c'est courir le risque qu'il y ait plusieurs dates identiques dans la table et que dans ce cas, le navigateur d'évènements reste bloqué sur un évènement ou en oublie. Chose improbable, me direz-vous, mais mes codes sont connus pour avoir très peu de failles et le fait de savoir que j'en laisse volontairement une derrière moi me froisse. Je ne tiens pas non plus à limiter ma table en configurant le champs "date" en mode "UNIQUE". Je cherche donc une solution  pointue, souple et sûre.

L'idéal serait de pouvoir faire une requête avec la date en condition en précisant à quelle clé commencer, sans toutefois devoir utiliser d'opérateur de comparaison pour cette dernière. Vous avez mal à la tête ? Moi aussi. Si seulement le mot clé "LIMIT" acceptait des conditions plutôt que des entiers, ce serait plus simple, car on donnerait à une requête une condition de départ (on limite la sélection au premier enregistrement qui la vérifie) et la condition d'itération (on continue tant que la condition est remplie et qu'il reste des enregistrements) , tout en mettant à disposition une variable prédéfinie OFFSET qui contiendrait donc l'offset de l'enregistrement en cours de traitement par MySQL :

SELECT * FROM event WHERE date> = une_date ORDER BY date LIMIT cle= une_cle , OFFSET< = 2

Dans cette requête imaginaire, on sélectionnerait toutes les dates à partir d'une date donnée, on les trierait par ordre chronologique (et implicitement par ordre d'insertion dans la table), on limiterait la sélection en commençant par l'enregistrement qui a une clé donnée et en terminant lorsque l'offset atteint 2. Le deuxième enregistrement ainsi sélectionné, s'il existe, serait celui recherché. Ce procédé serait sans faille.

Une solution qui marche est de procéder de la manière suivante, avec cet exemple de script en PHP :

$cle=   // mettre ici la cle de l'enregistrement courant
$date=  // mettre ici la date de l'enregistrement courant au format SQL 'yyyy-mm-dd hh:mm:ss'
$requete= "SELECT * FROM event WHERE date>= '$date' ORDER BY date";
$resultat = mysql_query($requete);  //effectuer la requête
if ($resultat) // si la requête est un succès
    while($enregistrement = mysql_fetch_array($resultat))  // alors tant que le résultat de la requête contient des enregistrements
          if($enregistrement['cle']== $cle)  // vérifier si l'enregistrement est l'enregistrement courant
                $enregistrement_recherche= mysql_fetch_array($resultat);  // auquel cas l'enregistrement suivant dans le résultat, s'il existe, est celui qu'on cherche

Seulement, cette solution peut s'avérer gourmande en ressources si la table est d'une taille imposante. Pour limiter la casse, on peut effectuer une requête préalable pour connaitre la premiere date strictement supérieure à celle que contient l'enregistrement courant, et ensuite l'utiliser dans la clause "WHERE" de la requête qui cherche les enregistrements suivants pour ne pas sélectionner les dates encore supérieures puisque de toute évidence, elles ne nous intéresseront pas.

Tout ceci m'amène enfin à ma question, que vous aurez sûrement deviné : connaissez-vous une manière de traduire ce que je cherche en une requête MySQL, si seulement c'est possible ? Sinon, si vous pensez à un script PHP moins gourmant, bien que je ne vois pas comment c'est possible, je suis également preneur.

Désolé d'être aussi exigeant, mais ce n'est pas la première fois que je me prend la tête sur le sujet.

5 réponses

nicomilville Messages postés 3472 Date d'inscription lundi 16 juillet 2007 Statut Membre Dernière intervention 28 février 2014 36
28 juin 2008 à 10:43
Salut,

Pour répondre sincèrement a ta question, non, je ne connais aucune requête qui est capable de faire ce que tu demande, et je ne connais pas non plus de script php plus souple !

Tu as essayé de faire une requête avec CASE et WHEN ?

a++

Si la réponse vous convient, pensez : Réponse acceptée !
3
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
29 juin 2008 à 03:51
Quoi ? Non seulement mon manuel MySQL ne liste que ses chapitres principaux, a un glossaire on ne peut plus incomplet, mais en plus il omet des notions aussi importantes que les variables ? J'hallucine !

Après une documentation plus sérieuse et quelques tests, il n'est pas possible de lire et d'écrire dans une variable au sein de la même instruction. Donc les variables SQL me sont d'une parfaite inutilité. J'ai tenté de ruser mais le fait est que même si on affecte une valeur à une variable à un quelconque emplacement d'une instruction SELECT, on ne pourra récupérer cette valeur qu'à l'instruction suivante, avant quoi la variable garde sa valeur initiale quoi qu'il arrive. Avec une autre version de SQL, j'aurais pu contourner cette limitation, mais bon, je ne vais pas commencer à écrire du code aussi peu portable, c'est un coup à avoir de mauvaises surprises.

De plus, après sérieuse vérification, c'est à dire après avoir parcouru l'intégralité du manuel en ligne de MySQL, il n'existe pas d'option pour la commande SELECT afin de commencer ou terminer la sélection à partir du moment où une condition est remplie. Pas moyen non plus de connaitre l'offset d'un enregistrement au sein d'une table, d'un groupe d'enregistrements ou d'une sélection.

Le sujet est donc à priori clôt, et la seule solution est à priori le script PHP que j'ai donné dans le message original.

Donc on va pouvoir discuter ici à loisir sans se préoccuper des hors sujets. J'expliquerai mon projet de langage de programmation lors de mon prochain passage sur ce site, et pourquoi il est lié à la notion de base de données.
3
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
28 juin 2008 à 19:56
Non, je n'avais pas pensé à cette syntaxe. Je vais me pencher dessus mais je ne pense pas que ça fera l'affaire. En théorie, si on utilise une condition WHERE, quelle que soit sa forme, SQL va tenter de la vérifier pour chaque enregistrement. Or, si j'avais imaginé une forme de LIMIT qui utilise des conditions dont la première n'est applicable que jusqu'à ce qu'elle soit vérifiée une première fois, c'est bien parce que lorsque l'on a identifié l'enregistrement "actuel", qui est identifié par une clé, la condition qui se charge de cette identification ne doit plus être utilisée après sinon SQL ne sélectionnera pas l'enregistrement suivant qui est celui qui nous intéresse réellement. On aurait pu également contourner le problème si le SQL était pourvu au moins d'un système de variables, ce qui m'aurait permis de faire une condition plus souple, mais pour autant que je sache, ce n'est pas le cas. C'est pourquoi s'il existe une solution à mon problème, elle passe théoriquement par un mot clé ou une fonction qui ne dépend pas de l'enregistrement en cours de traitement par SQL lors de la requête.

Si seulement il était possible d'obtenir l'offset d'un enregistrement au sein d'une table ou d'une sélection, alors on pourrait imbriquer trois SELECT qui feraient respectivement à partir du plus imbriqué : sélection des enregistrements via leur dates à partir de la date de l'enregistrement courant avec tri chronologique, sélection de l'offset de l'enregistrement courant retrouvé au sein de la dernière sélection avec sa clé, et finallement à nouveau sélection via les dates à partir de la date de l'engistrement courant avec tri chronologique mais limité ce coup-ci à un enregistrement avec pour offet celui que l'on a séléctionné plus un.

Je crois que je suis confronté à une des nombreuses insuffisances de ce langage qui aurait bien besoin d'une mise à jour majeure. Je ne comprend pas par exemple qu'il ne soit pas pourvu d'un choix plus large de fonctions, comme des fonctions HTML, XML, traitement des accents... Tout l'intérêt d'avoir un gestionnaire de base de données, c'est qu'elle est sencée être optimisée pour effectuer des traitements et des sélections de grandes quantités données. A partir du moment où on nous oblige à travailler dans le script hôte plutôt qu'avec des instructions SQL, il y a une grosse perte de performances. Du reste je trouve que nous obliger à passer par le langage SQL au lieu de nous laisser un contrôle plus manuel de ses fonctionnalités nous impose également une déperdition de performances, puisqu'il faut faire intervenir un analyseur syntaxique dont on aurait très bien pu se passer. Croisons les doigts pour qu'un jour tout ça soit repensé.

J'allais vous parler du langage de programmation que j'avais commencé à développer il y a quelques années et que j'espère pouvoir reprendre un jour, mais je crois que le moment est mal choisi pour raconter ma vie et j'ai déjà pollué un autre sujet ce matin. Une autre fois peut-être.

Merci [auteur/NICOMILVILLE/1109562.aspx nicomilville]pour t'être penché sur la question et d'avoir pris le temps de le comprendre le problème.
0
nicomilville Messages postés 3472 Date d'inscription lundi 16 juillet 2007 Statut Membre Dernière intervention 28 février 2014 36
28 juin 2008 à 21:40
Re,

Tu ne me soul pas, ça ne me dérangerai pas que tu m'en dise plsu sur ton langage...

Je vais quand même revenir sur ce que tu as dit a propos des variables, si tu es sous mysql, tu peus utiliser des variables que tu déclare comme ça :

SET @variable = 'valeur';

De rien...

a++

Si la réponse vous convient, pensez : Réponse acceptée !
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
nicomilville Messages postés 3472 Date d'inscription lundi 16 juillet 2007 Statut Membre Dernière intervention 28 février 2014 36
29 juin 2008 à 09:17
ok,

Bonne chance

a++

Si la réponse vous convient, pensez : Réponse acceptée !
0
Rejoignez-nous