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

PHP & Base de données Discussion :

Vérifier qu'un enregistrement existe, faut-il utiliser fetchColumn ? [PDO]


Sujet :

PHP & Base de données

  1. #1
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut Vérifier qu'un enregistrement existe, faut-il utiliser fetchColumn ?
    Bonjour,

    Voici mon code pour vérifier si un enregistrement existe.

    Mon code fonctionne mais faut t'il plutôt privilégier fetchColumn ?

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $idann = (int) $_GET['idann'];
     
    $req = $pdo->prepare('SELECT a.idann, a.content, a.level, a.location, a.amount, u.username, u.email
    FROM ad a
    INNER JOIN users u ON a.idmbr = u.idmbr
    WHERE a.idann = ?');
    $req->execute([$idann]);
    $ad = $req->fetch();
     
    if (!$ad) {
        header('Location: index.php?p=ad/search');
        exit();
    }

    et je ne comprends pas bien aussi le rowcount, http://php.net/manual/fr/pdostatement.rowcount.php regardez l'exemple numéro 2 "Comptage des lignes retournées par une requête SELECT"

    Je cite la doc php :

    Pour la plupart des bases de données, PDOStatement::rowCount() ne retourne pas le nombre de lignes affectées par une requête SELECT. À la place, utilisez PDO::query() pour faire une requête SELECT COUNT(*), puis utilisez PDOStatement::fetchColumn() pour récupérer le nombre de lignes retournées. Votre application peut ainsi effectuer la bonne action.
    donc je ne comprends pas, mon code fonctionne oui, mais est-ce qu'il existe une méthode plus "propre" pour vérifier qu'un enregistrement existe ?

    merci pour votre aide.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT COUNT(id) AS nbr_lignes WHERE ...


    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $req = $pdo->prepare("SELECT COUNT(a.idann) AS nbre_lignes
    FROM ad a
    INNER JOIN users u ON a.idmbr = u.idmbr
    WHERE a.idann = ? ;");
    $req->execute([$idann]);
    $ad = $req->fetch();
     
    $nbreLignes = $ad['nbre_lignes'];
     
    if ($nbreLignes!=1) {
        header('Location: index.php?p=ad/search');
        exit();
    }

    N.B.

    1/ Je n'ai jamais utilisé fetchColumn() !

    2/ Malgré l'avertissement, j'utilise aussi (sans problème jusqu'ici) rowCount() pour mes requêtes SELECT.
    Dernière modification par Invité ; 01/08/2016 à 20h03.

  3. #3
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    ok donc quasi la même chose que mon code mais avec COUNT dans la requête..

    bizarre que la doc php effectue la même tache en 2 étapes .. alors que ton code et le mien en une seule. Du coup comment choisir, php laisse trop de liberté sur la façon de faire.. et selon moi ce n'est pas toujours bon !

    Façon de faire de la doc php :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?php
    $sql = "SELECT COUNT(*) FROM fruit WHERE calories > 100";
    if ($res = $conn->query($sql)) {
     
       /* Récupère le nombre de lignes qui correspond à la requête SELECT */
       if ($res->fetchColumn() > 0) {
     
          /* Effectue la vraie requête SELECT et travaille sur le résultat */
          $sql = "SELECT nom FROM fruit WHERE calories > 100";
          foreach ($conn->query($sql) as $row) {
          print "Nom : " .  $row['NOM'] . "\n";
          }
       }
       /* Aucune ligne ne correspond -- faire quelque chose d'autre */
       else {
          print "Aucune ligne ne correspond à la requête.";
       }
    }
     
    $res = null;
    $conn = null;
    ?>

  4. #4
    Invité
    Invité(e)
    Par défaut
    1/ Comme je t'ai dit, je n'ai (jusqu'ici) jamais eu de souci avec rowCount() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?php
    $sql = "SELECT nom FROM fruit WHERE calories > 100";
    $res = $conn->query($sql)
    $nbr_res = $res->rowCount();
     
    if ($nbr_res > 0) {
     
       foreach( $row = $res->fetch() )
       {
       ....
       }
    }
    2/ je n'utilise ""SELECT COUNT(id)..." que pour vérifier qu'un enregistrement existe (pour savoir si une "article" existe, par exemple, avant d'en afficher le détail), sans avoir besoin de récupérer des infos (champs).

    Après... chacun son style, chacun sa méthode et ses habitudes


    Ne pas négliger de passer par une requête préparée quand elle contient des valeurs "externes" (passées par l'utilisateur, en POST ou GET) !

  5. #5
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 383
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 383
    Points : 10 411
    Points
    10 411
    Par défaut
    Salut,

    La doc sur rowCount est placée dans un contexte général. Dans l'univers des systèmes de gestion de bases de données, une minorité d'entre eux ont implémentés la fonction rowCount. C'est ce que dit la doc en montrant une méthode universelle qui fonctionnera quelque soit le sgbdd. Cela dit dans le contexte du web avec php on utilise très souvent mysql ou apparenté et ces systèmes renvoient la bonne valeur pour cette fonction. Donc c'est très simple si tu ne connais pas la base de donnée qui sera utilisée avec ton code, évites d'utiliser rowCoount, par contre si c'est pour une bdd dont tu sais qu'elle gère cette fonction c'est quand même plus pratique que de faire deux requêtes.

    Après quand il s'agit simplement de savoir si un enregistrement existe, l'important est de ne pas collecter des champs qui ne servent à rien si tu ne les exploitent pas par la suite. C'est ce processus qui prend du temps pour la requête et c'est pour cela que la doc php montre le cas typique d'une requête avec SELECT COUNT(*) qui ne sélectionne aucun champ.

  6. #6
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    oui en effet, je comprends le fonctionnement mais j'ai du mal à le mettre en pratique dans mon cas car j'ai une problématique supplémentaire. Est-ce que dans mon cas il faut mieux récupérer les infos au même moment que la verif ou bien dans une autre requête plus bas comme dans l'exemple sur la doc ? Même si bien-sûr la function rowCount est implémenté dans mysql.

    Je pense qu'il est préférable de vous montrer le code complet de ma page (mon code fonctionne) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    <?php
    session_start();
     
    $idann = (int) $_GET['idann'];
     
    //--- vérifie qu'un enregistrement existe ET récupère les infos.
    $req = $pdo->prepare('SELECT a.idann, a.content, a.location, a.amount, a.dateann, a.phone, u.username, u.email
    FROM ad a
    INNER JOIN users u ON a.idmbr = u.idmbr
    WHERE a.idann = ?');
    $req->execute([$idann]);
    $ad = $req->fetch();
     
    //--- si pas de résultat..
    if (!$ad) {
        header('Location: index.php?p=ad/search');
        exit();
    }
    //--- end
     
    if (!empty($_POST)) {
     
        if (empty($_POST['email']) || !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
            $_SESSION['flash']['danger'] = 'Votre email n\'est pas valide';
        }
     
        if (empty($_SESSION['flash'])) {
            //mail($_POST['email'], 'sujet du mail', "contenu du mail");
            $_SESSION['flash']['success'] = 'Votre message a été envoyé à l\'annonceur !';
            header('Location: index.php?p=ad/view&idann='.$idann.'');
            exit();
        }
    }
     
    $title_page = 'Fiche';
     
    ?>
     
    <h1>Fiche</h1>
     
    <div class="row">
        <div class="col-md-8">
            <div class="panel panel-default">
                <div class="panel-body">
                    <?= htmlspecialchars($ad->content); ?>
                </div>
                <!-- List group -->
                <ul class="list-group">
                    <li class="list-group-item">Ville : <?= htmlspecialchars($ad->location); ?></li>
                    <li class="list-group-item">Tarif : <?= $ad->amount; ?> €</li>
                </ul>
                <div class="panel-footer">Mise en ligne le <?= htmlspecialchars($ad->dateann); ?></div>
            </div>
        </div>
        <div class="col-md-4">
            <h2>Contacter <?= htmlspecialchars($ad->username); ?></h2>
     
            <p class="lead"><span class="glyphicon glyphicon-earphone" aria-hidden="true"></span> <?= implode(' ', str_split($ad->phone,2)); ?></p>
     
            <form action="" method="post">
                <div class="form-group">
                    <label class="sr-only" for="name">Nom et prénom</label>
                    <input type="text" name="name" value="<?= empty($_POST['name']) ? '' : htmlspecialchars($_POST['name'], ENT_QUOTES); ?>" class="form-control" id="name" placeholder="Nom et prénom">
                </div>
                <div class="form-group">
                    <label class="sr-only" for="email">Votre email</label>
                    <input type="text" name="email" value="<?= empty($_POST['email']) ? '' : htmlspecialchars($_POST['email'], ENT_QUOTES); ?>" class="form-control" id="email" placeholder="Votre email">
                </div>
                <div class="form-group">
                    <label class="sr-only" for="content">Votre message</label>
                    <p id="helpBlock" class="help-block">Pensez à indiquer vos coordonnées téléphoniques pour que l'annonceur puisse vous contacter facilement.</p>
                    <textarea name="content" class="form-control" id="content" rows="6" placeholder="Votre message" aria-describedby="helpBlock"><?= empty($_POST['content']) ? '' : htmlspecialchars($_POST['content'], ENT_QUOTES); ?></textarea>
                </div>
                <button type="submit" class="btn btn-primary">Envoyer</button>
            </form>
        </div>
    </div>

  7. #7
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    L'optique "vérifier puis récupérer" est surtout utile lorsqu'on récupère un nombre important de lignes avec un nombre important de champs, ou si tu as besoin de connaitre le nombre de lignes avant de faire l'affichage.

    Par exemple, dans le cas d'une pagination, tu as besoin de savoir combien il y a de lignes au total (pour calculer le nombre de pages), mais tu ne veux en afficher qu'un petit nombre. Récupérer toutes les lignes pour pouvoir les compter et ensuite tronquer le tableau n'est pas une bonne approche. Si tu as 36 000 lignes en base et que tu veux juste les 10 premières, il vaut mieux un count, puis une récupération limitée. Sinon, ça revient à vider intégralement toutes les étagères du placard pour attraper le paquet de chips qui se trouvait sur l'étagère du bas.

    Dans ton cas, tu fais une recherche par identifiant. Tu peux donc trouver au maximum une ligne, avec seulement 8 champs à lire. Faire la récupération et la vérification en une seule requête ne devrait donc pas avoir d'impact.
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  8. #8
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 383
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 383
    Points : 10 411
    Points
    10 411
    Par défaut
    Oui dans ton cas tu n'as pas besoin de compter le nombre de lignes... pourquoi faire puisque tu sais que le résultat sera 0 ou 1 et que le test sur le fetch() sera suffisant pour obtenir ce résultat. Ton code est donc correct. Tu te poses un problème qui n'existe pas ici

  9. #9
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    ok les amis je comprends mieux le principe grâce a vos explications je ne change donc pas mon code.


  10. #10
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 383
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 383
    Points : 10 411
    Points
    10 411
    Par défaut
    Et pour terminer la petite histoire sur le comptage des lignes retournées, quand on attend un nombre raisonnable de réponses on peut utiliser fetchAll() pour retourner toutes les réponses directement dans un tableau. De sorte que dans ce cas tu peux utiliser un simple count() sur ce tableau pour trouver le résultat sans besoin de passer par un rowCount si tu tiens à éviter cette fonction.

  11. #11
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    ok merci pour les précisions

    et dernière question, ce n'est pas grave que la requête de récupération soit en haut de page, et que l'utilisation/affichage des données soit en bas de page comme dans mon code ?

  12. #12
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 383
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 383
    Points : 10 411
    Points
    10 411
    Par défaut
    Non, c'est même recommandé de faire comme cela.

    Les requêtes doivent être exécutées de préférence en dehors du html pour permettre une exécution indépendante de la construction du code html et ainsi libérer les ressources le plus tôt possible pour solliciter le moins possible le serveur de sgbdd.

    Pour cette raison on récupère souvent tous les résultats d'une requête dans un tableau - avec un fetchAll() ou un while.. fetch() pour la construction d'un tableau sur mesure - ce qui permet de libérer les ressources de la connexion et on fait afficher le tableau dans le htm. Sinon elles ne seraient libérées qu'après la construction du html. Dans ton cas comme il n'y a qu'une ligne, la ressource est libérée dès le premier appel à fetch (la ressource se libère dès que tu as lu la dernière ligne).

    Enfin c'était l'ancienne école. Avec toutes les dernières optimisations c'est peut-être un peu moins important mais comme cela permet aussi de mieux organiser son code c'est toujours mieux que d'avoir du code php parsemé dans tout le html. On ne devrait trouver dans le html que des variables php ou des tableaux php, mais pas des requêtes ni d'autres traitements lourds, bref uniquement ce qui permet d'afficher directement des valeurs. C'est le cas dans ton code donc RAS.

    Après pour chipoter on pourrait dire que c'est mieux de faire les requêtes dans un bloc try/catch pour mieux gérer les erreurs, mais bon chaque chose en son temps...

  13. #13
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    ok merci ABCIWEB j'ai appris des choses sur le traitement et la libération des ressources

    Après pour chipoter on pourrait dire que c'est mieux de faire les requêtes dans un bloc try/catch pour mieux gérer les erreurs, mais bon chaque chose en son temps...
    une fois mon appli terminée, j'envisage de le diviser en mvc pour une meilleure gestion etc.. puis par la suite pourquoi pas ré écrire l'appli en pdo. Mais bon tu as raison, chaque chose en son temps...

    en résumé, je fais une appli de petites annonces, il en existe beaucoup déjà mais je suis trop difficile^^ et je veux quelque chose de très simple.. juste le nécessaire et très épuré.

  14. #14
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 383
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 383
    Points : 10 411
    Points
    10 411
    Par défaut
    Citation Envoyé par bndd24 Voir le message
    ok merci ABCIWEB j'ai appris des choses sur le traitement et la libération des ressources
    C'est dans le but d'économiser le serveur de base de données, c'est lui qui rend l'âme en premier avec le message "to much connexions" si trop de connexions simultanées au site d'où l'intérêt d'avoir des requêtes optimisées et de rendre la main le plus tôt possible.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2007] Vérifier si un enregistrement existe
    Par Mat08 dans le forum IHM
    Réponses: 0
    Dernier message: 06/07/2010, 10h16
  2. Vérifier si un enregistrement existe dans une table
    Par developpeur_débutant dans le forum PL/SQL
    Réponses: 4
    Dernier message: 08/06/2010, 12h05
  3. [PDO] Vérifier que l'enregistrement existe avant de l'exploiter
    Par php_de_travers dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 31/12/2009, 10h28
  4. [MySQL] Vérifier si un enregistrement existe
    Par mrsoyer dans le forum PHP & Base de données
    Réponses: 6
    Dernier message: 09/05/2008, 15h09
  5. [SQL] Vérifier si un enregistrement existe
    Par Mamath76 dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 28/08/2007, 14h22

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