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

Requêtes MySQL Discussion :

Obtenir id précédent/suivant alors que certains id manquent?


Sujet :

Requêtes MySQL

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut Obtenir id précédent/suivant alors que certains id manquent?
    Bonjour,

    Je suis en train de faire un petit script d'affichage type "affichage de news" (je prends cet exemple car il me semble être le plus parlant, pour une représentation visuelle de la chose vous pouvez vous rendre sur la boîte à rêves).
    J'affiche des listes de "news" sur des pages et chaque titre de news est linké vers une page sur laquelle s'affiche la "news" en fonction de son $id.
    Tout ça marche bien.

    J'aimerais maintenant afficher, sur la page d'affichage individuel, les titres de la news précédente et de la news suivante (linkées vers les pages d'affichage individuel bien sûr).

    Mes news comportent les éléments suivants :
    - id
    - titre
    - activity ("on" ou "off")

    Mais les $id ne se suivent pas forcément ! Petite explication : certaines news sont offline et tous les id ne sont pas forcément attribués (certaines news pouvant être supprimées)...

    Je ne sais pas très bien comment m'y prendre pour obtenir les id et titre des news précédente et suivante. Une boucle php ? Existe-t-il une fonction MySQL permettant de faire ça directement (prendre l'id le plus proche en valeur supérieure ou inférieure par exempel) ? Voire même un petit bout de code pouvant m'aider ?

  2. #2
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut Re: Obtenir id précédent/suivant alors que certains id manqu
    Je vois 3 façons de faire, chacune avec leurs avantages et leurs inconvénients.

    1ère solution:

    Tu fais simplement un:
    Ensuite tu parcours les résultats en gardant une news en "tampon", jusqu'à tant que tu tombes sur la news d'id recherché. Ainsi tu affiches la news précédente, l'actuelle et la suivante et tu t'arêtes.

    Le problème, c'est qu'en faisant cela, tu es obligé de retourner tous les résultats de la requête, ce qui fait énormément de communications réseaux entre PHP et MySQL. Pour cette raison, cette solution n'est pas du tout élégante.

    La deuxième solution est plus compliquée d'un point de vue algorithmique, mais abouti à moins d'échanges réseau entre le serveur MySQL et le serveur qui fait tourner PHP (probablement Apache).

    2ème solution:

    Pour obtenir la news précédente:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT * FROM news
    WHERE id<$idCherche
    ORDER BY id DESC
    LIMIT 1
    Pour obtenir la news courante et la suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM news
    WHERE $idCherche<=id
    LIMIT 2
    On fait l'UNION des 2:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    (SELECT * FROM news
    WHERE id<$idCherche
    ORDER BY id DESC
    LIMIT 1)
     
    UNION
     
    (SELECT * FROM news
    WHERE $idCherche<=id
    LIMIT 2)
    Avantage: on ne retourne que les 3 news qui nous intéressent
    Inconvénient: Ca fait plus de boulot pour MySQL


    3ème solution:

    On prend le meilleur des 2 solutions précédentes: on prend l'algo de la première solution, que l'on implémente sous forme d'une procédure stockée.

    Avantages:
    - Algo optimal
    - Très peu de communications réseau (c'est MySQL qui fait tout et qui renvoie seulement les 3 enregistrements qui nous intéressent)

    Inconvénients:
    - Il faut que l'environnement le permette (MySQL 5)
    - C'est difficile à mettre en place

    ***

    Je pense qu'il y a de grandes chances pour que tu optes pour la solution 2 (juste ma requête à recopier et peu de communication réseau).

    La solution 1 ne peut être envisagée que si PHP et MySQL sont sur la même machine. De plus, cela demande de la programmation PHP supplémentaire: on l'oublie !

    Tu peux toujours tenter l'expérience PROCEDURE STOCKEE, mais je te préviens que le chemin sera long. Je m'interroge même sur la faisabilité d'une telle procédure (Pb: garder en mémoire la ligne précédente afin de l'ajouter au résultat final).

    Voilà, je crois avoir répondu de manière exhaustive à ta question. Ma préférence: la solution 2.
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  3. #3
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    Quelques remarques

    1)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM news 
    WHERE $idCherche<=id 
    LIMIT 2
    devrait être remplacé par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT * FROM news 
    WHERE $idCherche<=id 
    ORDER BY Id
    LIMIT 2
    2) Je ne sais pas pour mySQL, mais la norme interdit la clause ORDER BY dans les requêtes internes d'une UNION

    3) Si c'est possible sous mySQL, je mettrais UNION ALL à la place de UNION, même si, sur 3 lignes, cela aura peu d'impact

    4) Si c'est possible, la solution 2 est la plus performante, surtout s'il y a un index sur Id.
    J'affirme péremptoirement que toute affirmation péremptoire est fausse
    5ième élément : barde-prince des figures de style, duc de la synecdoque
    Je ne réponds jamais aux questions techniques par MP

  4. #4
    Membre éclairé

    Profil pro
    Inscrit en
    Mai 2005
    Messages
    414
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 414
    Points : 671
    Points
    671
    Par défaut
    Je complète juste la réponse très pertinente de Mediat

    3/ Le "Union" impose une activité de tri au niveau du moteur car elle supprime les doublons alors que le "Union ALL" non d'où cette remarque de performance.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Merci beaucoup pour vos réponses . La solution 2 est donc celle qui convient .

    Par contre je ne comprends pas quelques petites choses :

    1°) Comment obtient-on le $idCherche ?

    2°) Mon code va ressembler à ça ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $sql = "(SELECT * FROM reves_reves WHERE id<$idCherche ORDER BY id DESC LIMIT 1) UNION (SELECT * FROM news WHERE $idCherche<=id ORDER BY id LIMIT 2)";
    $req = mysql_query($sql) or die('Erreur SQL !<br>'.$sql.'<br>'.mysql_error());
    $data = mysql_fetch_assoc($req);
    (ma table s'appelant reves_reves).

    Avec ça il me fait l'erreur :

    Erreur SQL !
    (SELECT * FROM reves_reves WHERE id< ORDER BY id DESC LIMIT 1) UNION (SELECT * FROM news WHERE <=id ORDER BY id LIMIT 2)
    You have an error in your SQL syntax near '(SELECT * FROM reves_reves WHERE id< ORDER BY id DESC LIMIT 1) UNION (SELECT * F' at line 1
    C'est parce que $idCherche n'est pas dénifi, non :- ?

  6. #6
    Membre émérite Avatar de Maximil ian
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    2 622
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 2 622
    Points : 2 973
    Points
    2 973
    Par défaut
    Citation Envoyé par Médiat
    2) Je ne sais pas pour mySQL, mais la norme interdit la clause ORDER BY dans les requêtes internes d'une UNION
    C'est possible sous MySQL.

    Citation Envoyé par yazerty
    C'est parce que $idCherche n'est pas dénifi, non :- ?
    Oui ou parce que ta version de MySQL ne supporte pas l'UNION (MySQL >= 4.0)
    Pensez au bouton

  7. #7
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut
    Ok, c'est bien, pas mal de réactions, toutes très constructives.

    Médiat, par rapport à ce que tu dis:
    1) Les enregistrements étant insérés dans l'ordre des id, je n'avais pas jugé bon de mettre un ORDER BY, question de performance

    2) Ca je ne savais pas. Au pire on fait 2 requêtes et c'est terminé !

    3) Pour le UNION ALL, c'est une très bonne idée !

    ***
    Maintenant yazerty:
    1) Ce que j'ai noté $idCherche, c'est l'id que tu cherches !! (pourtant le nom est assez explicite! )

    2) Déjà, oui, définit $idCherche. Par contre c'est bizarre, il semble ne pas accepter la parenthèse/l'UNION....

    Ce que tu fais:
    - si tu peux, tu testes la requête dans phpMAdmin
    - tu testes les requêtes séparément
    - au pire, tu fais 2 requêtes (tu mets tes requêtes dans un tableau et tu exécutes chacune des requêtes du tableau séparément. Comme ça t'as juste à faire une boucle)
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Oui oui c'est explicite mais ce que je ne comprends pas c'est que $idCherche c'est justement ce que je recherche (le numéro de l'id situé avant ou après qui est on(line)) .

    Sinon je suis sur un petit 60gp OVH pour ce site. Je n'ai pas trouvé leur numéro de version MySQL mais leur ai posé la question par mail...

    ps : je suis désolé de poser des questions qui peuvent paraître évidentes mais je recommence à coder un peu depuis 2 jours et mon dernier code remonte à près d'un an et demi et à l'époque je me limitais à des SELECT/INSERT on ne peut plus basiques...

  9. #9
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut
    Citation Envoyé par yazerty
    Oui oui c'est explicite mais ce que je ne comprends pas c'est que $idCherche c'est justement ce que je recherche (le numéro de l'id situé avant ou après qui est on(line)) .
    T'as pas dû tout comprendre... $idCherche, c'est l'id du "rêve" courant et la requête te renvoie le rêve précédent, le rêve courant et le rêve suivant. Si c'est plus clair pour toi, renomme-le $idCourant

    Citation Envoyé par yazerty
    Sinon je suis sur un petit 60gp OVH pour ce site. Je n'ai pas trouvé leur numéro de version MySQL mais leur ai posé la question par mail...
    C'est un problème secondaire ça, en faisant plusieurs requêtes, pas de problème d'UNION.
    Pour le numéro de version, pas besoin de mail:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SHOW VARIABLES LIKE "version"
    Citation Envoyé par yazerty
    ps : je suis désolé de poser des questions qui peuvent paraître évidentes
    Pas si évidente que ça (la preuve: j'ai posté 3 solutions que j'ai dû détailler pour déterminer laquelle semble la meilleure). Et rassure toi, on a connu bien pire !
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    C'est donc la version 3.23.58-log ... Un peu en retard OVH, un peu ...

    Je vais donc séparer la chose en deux comme l'UNION n'est supporté qu'à partir de la version 4.

    Pour $idCherche en fait j'ai déjà mon $id courant, qui se nomme $id. Il me sert à afficher le rêve en cours.
    De plus je ne veux que l'id et le titre du rêve suivante/précédente. Je ne sélectionne donc que "id,titre" dans ma requête.

    Je fais donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $sql = "SELECT id,titre FROM reves_reves WHERE id<$id ORDER BY id DESC LIMIT 1";
    $req = mysql_query($sql) or die('Erreur SQL !<br>'.$sql.'<br>'.mysql_error());
    $data = mysql_fetch_assoc($req);
    $titre_plus_ancien = $data['titre'];
    echo "Titre plus ancien : $titre";
    Mais le titre alors affiché est le titre du rêve affiché sur la même page .

  11. #11
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut
    Pourtant tu as bien fait: WHERE id<$id (STRICTEMENT inférieur). Tu es sûr de ne pas avoir deux fois le même rève? (affiche les id, tu seras plus sûr)

    Puisque tu n'as pas besoin du rêve courant, dans le deuxième cas tu feras WHERE id>$id (strictement supérieur).
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $sql_plus_ancien = "SELECT id,titre FROM reves_reves WHERE id<$id ORDER BY id DESC LIMIT 1";
    $req_plus_ancien = mysql_query($sql_plus_ancien) or die('Erreur SQL !<br>'.$sql_plus_ancien.'<br>'.mysql_error());
    $data_plus_ancien = mysql_fetch_assoc($req_plus_ancien);
    $id_plus_ancien = $data_plus_ancien['id'];
    $titre_plus_ancien = $data_plus_ancien['titre'];
    echo "<p>Id courant : $id - Id_plus_ancien : $id_plus_ancien - Titre plus ancien : $titre";
    Résultat affiché :
    Id courant : 427 - Titre courant : Dent sur pivot - Id_plus_ancien : 426 - Titre plus ancien : Dent sur pivot
    (le titre du rêve courant est "Dent sur pivot", l'id inférieur est bien le 426)

    Il trouve bien l'id mais pas le titre, bizare non ?

  13. #13
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut
    Citation Envoyé par yazerty
    Il trouve bien l'id mais pas le titre, bizare non ?
    Bon ben cherche pas: t'as deux fois le même rêve ! (donc ça vient pas de la requête)

    Note: t'as vraiment des gens qui font des rêves bizarres. Ils ont fumé quoi?
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Mouarf j'ai mis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Titre plus ancien : $titre


    Ca a l'air de marcher ! Je vous tiens au courant...

    ps : lool

  15. #15
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 109
    Points : 57
    Points
    57
    Par défaut
    Wonderbar !

    Un très graand merci à tout le monde !

    Pour ceux que ça intéresse le résultat est directement visible sur les pages d'affichage individuelles de la boîte à rêves...

  16. #16
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut
    Citation Envoyé par yazerty
    Mouarf j'ai mis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Titre plus ancien : $titre
    C'est vrai que c'est très drôle !

    Citation Envoyé par yazerty
    Wonderbar !
    En Allemand, c'est plutôt "wunderbar" qu'on dit.

    Citation Envoyé par yazerty
    Un très graand merci à tout le monde !
    Ben de rien !
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  17. #17
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    Citation Envoyé par pcaboche
    1) Les enregistrements étant insérés dans l'ordre des id, je n'avais pas jugé bon de mettre un ORDER BY, question de performance
    Je te déconseille fortement de te baser sur un ordre implicite dans tes requêtes SQL, tu ne sais pas comment les données ont été enregistrées, car les espaces libérées peuvent-être réutilisées...
    J'affirme péremptoirement que toute affirmation péremptoire est fausse
    5ième élément : barde-prince des figures de style, duc de la synecdoque
    Je ne réponds jamais aux questions techniques par MP

  18. #18
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Points : 9 716
    Points
    9 716
    Par défaut
    Médiat, tu as raison, il vaut mieux rester prudent (d'autant qu'avec les index, le tri se fait très rapidement)
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

Discussions similaires

  1. Réponses: 3
    Dernier message: 02/12/2012, 18h47
  2. Réponses: 4
    Dernier message: 13/08/2005, 10h20
  3. RecordCount = -1 alors que SELECT = OK
    Par Dionyzos dans le forum Bases de données
    Réponses: 5
    Dernier message: 01/03/2005, 14h27
  4. [Oracle 8i] ne garder que certains enregistrements (COUNT ?)
    Par delphim dans le forum Langage SQL
    Réponses: 13
    Dernier message: 23/02/2005, 14h30
  5. 1 Table, Des doublons, ne rertenir que certains d'entre eux
    Par Dragano dans le forum Langage SQL
    Réponses: 3
    Dernier message: 26/01/2005, 12h06

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