Création d'un QCM

Création d'un QCM - PHP - Programmation

Marsh Posté le 02-12-2020 à 15:48:38    

Salut mes devs szurs.
 
Toujours dans le cadre de mon projet, je suis en train de me casser la tête pour créer un QCM.
 
J'ai créé 2 tables.
 
Dans la 1ere, j'ai injecté les questions avec un id_question propre à chaque question.
J'ai également injecté les réponses (2 mini et 4 maxi) avec un id_reponse.
 
Dans la 2eme table, je stocke l'id de l'utilisateur qui va passer le test, avec l'enregistrement de l'id_question, id_reponse, a chaque fois que l'utilisateur répondra à la question.
 
Voici la structure de la table QCM :
 
https://i.ibb.co/v16Y1nC/questions.jpg
 
Voici la structure de la table qui enregistre les réponses :
 
 
https://i.ibb.co/DV9Hn7J/reponses.jpg
 
 
 
Dans l'idée ce que je veux faire :
 
Lorsque l'utilisateur démarre le test :
 
Une question est tirée au hasard de la table QCM, avec les réponses associées.  
Lorsque l'utilisateur répond à une question : l'id de la question et l'id la réponses, entre autres, sont enregistrées dans la base.
 
Ca j'arrive à le faire avec l'attribut 'ORDER BY RAND() LIMIT 0,1' dans la requete SQL. Je récupère l'ID de la question qui s'est affichée et je fais chercher les réponses associées à l'ID de la question.
 
Par contre là où je bloque, c'est que je n'arrive pas à faire en sorte que la question à la quelle l'utilisateur a déjà répondue ne s'affiche pas une deuxième fois.
 
 
Une des pistes qui revient souvent sur les internets, c'est la création d'un array qui embarquera tous id_questions et qui, au fur et à mesure des réponses, se réduira jusqu'à épuisement parce que l'utilisateur aura répondu à toutes les questions.  
 
Et une requete SQL qui piochera au hasard dans cet array l'id de la question disponible.
 
 
Mes requêtes actuelles :
 

Code :
  1. $questions = array ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14');    // j'ai 14 questions en tout. Comme je ne sais pas créer la boucle pour générer l'array, je l'ai créé en dur.  
  2. $imploded_q = join("','",$questions);
  3. $resultat = $mysqli->query("SELECT id_question FROM resultats where id_membre='$id_membre' AND statut ='0' AND id_question NOT IN ('$imploded_q');" ) or die('Erreur SQL !'.$resultat.'<br>'.mysqli_error($mysqli));;
  4. while ($array = $resultat->fetch_assoc())
  5. {
  6. $reponse = $array['id_question'].',';
  7. }


 
Pour générer aléatoirement la question :
 

Code :
  1. $question = mysqli_fetch_assoc(mysqli_query($mysqli,("SELECT * FROM tests WHERE id_reponse='0' AND id_question != '$reponse' ORDER BY RAND() LIMIT 0,1" )))


 
 
Merci pour votre aide.
 
 


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 02-12-2020 à 15:48:38   

Reply

Marsh Posté le 02-12-2020 à 16:13:08    

Ton schéma de base n'est pas bon, pour être un peu plus propre et optimisé (pas de donnée redondantes et identiques) tu devrais avoir :
- une table test avec id_test / lib_test.
- une table question avec id_question (id_test clef etrangere), lib_question
- une table réponse avec id_reponse (id_question  clef etrangere), lib_reponse
- une table member_reponse avec id (clef unique auto increment), id_question, id_reponse , id_member (les trois en clef etrangere et unique)
 
De cette façon tu peux trouver a chaque page toutes les réponses de l'utilisateur auquel il a déjà répondu (ou celle auquel il n'a pas répondu avec un LEFT JOIN [...] WHERE id_member = NULL.
 
Fait quelques tutos sur les bons schémas de base de donnée et les jointures.


---------------
D3
Reply

Marsh Posté le 02-12-2020 à 16:24:50    

Merci pour ta réponse.

 

Je veux bien te croire que les bases sont loin d'être optimisées, cependant je ne vois pas en quoi le fait de les découper résoudra ma problématique de tirage aléatoire de la question qui n'a pas encore eu de réponse.

 

Du moins, je ne vois pas comment je pourrais le faire.

 

Ce que j'ai oublié de préciser, c'est que chaque question à des réponses bien spécifiques qui lui sont rattachées.
Ce ne sont pas des réponses au hasard.


Message édité par La classe @ dallas le 02-12-2020 à 16:40:33

---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 02-12-2020 à 16:42:42    

Tu enregistres les réponses dans la base de donnée non ?
Donc avec une jointure tu devrais pouvoir trouver les id_question qui n'ont pas d'id_member et dont la jointure sera impossible (avec un ON ou WHERE id_member != $id_member par exemple).
 
Mais en vrai ce serait sans doute moins couteux en ressource de garder dans une session un array de questions répondu...


---------------
D3
Reply

Marsh Posté le 02-12-2020 à 16:55:26    

mechkurt a écrit :

Tu enregistres les réponses dans la base de donnée non ?
Donc avec une jointure tu devrais pouvoir trouver les id_question qui n'ont pas d'id_member et dont la jointure sera impossible (avec un ON ou WHERE id_member != $id_member par exemple).
 
Mais en vrai ce serait sans doute moins couteux en ressource de garder dans une session un array de questions répondu...


Oui oui.
Je vais voir la possibilité de split les bases créées comme tu me l'as suggéré.  
Ne te méprends pas, je suis content que tu m'aides. Je ne sais pas faire, du coup j'essaie de voir comment je peux mettre en pratique ta solution.
Merci à toi


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 02-12-2020 à 22:52:18    

Dans ta table QCM, c'est normal que on id_test, ça soit un int(1) alors que dans l'autre table, c'est un int(10) :??:
Au passage, tous tes id devraient être des unsigned  vu qu'ils vont être > 0 :o


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-12-2020 à 00:16:48    

rufo a écrit :

Dans ta table QCM, c'est normal que on id_test, ça soit un int(1) alors que dans l'autre table, c'est un int(10) :??:
Au passage, tous tes id devraient être des unsigned vu qu'ils vont être > 0 :o


Je dirai que oui. Il y a que 75 entrées environs dans la table qcm. Dans l'autre table c'est sensé être à l infini.

 

Ca change quelque chose ?


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 03-12-2020 à 08:11:45    

T'as conscience que INT(1), ça veut dire un INT affiché sur 1 chiffre ? Donc de 0 à 9 ? Pour aller à 75, ça va être un peu court :/
 
Par contre, je comprends pas pourquoi dans QCM, t'as un champ id qui est manifestement la clé primaire du QCM et un champ id_test. Dans la tablet des questions/réponses, je pensais que id_test était une clé étrangère pointant sur la table QCM d'où mon interrogation sur la différence de type.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-12-2020 à 09:08:08    

rufo a écrit :

T'as conscience que INT(1), ça veut dire un INT affiché sur 1 chiffre ? Donc de 0 à 9 ? Pour aller à 75, ça va être un peu court :/


Oui je suis conscient. id_test sera sur un digit. 1,2,3,4 en l'occurrence. :jap:

 
rufo a écrit :


Par contre, je comprends pas pourquoi dans QCM, t'as un champ id qui est manifestement la clé primaire du QCM et un champ id_test. Dans la tablet des questions/réponses, je pensais que id_test était une clé étrangère pointant sur la table QCM d'où mon interrogation sur la différence de type.


J aurai a terme 4 tests en tout. D ou id_test dans ma base. L id tout court c'est pour les entrées. :jap:.


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 03-12-2020 à 14:00:49    

Certes mais pourquoi dans ta table des réponses, tu as mis id_test en int(10) ? C'est pas cohérent.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 03-12-2020 à 14:00:49   

Reply

Marsh Posté le 08-12-2020 à 12:08:46    

Salut à tous.

 

Après une pause, car ma tête allait exploser, j'ai repris le developpement.

 

J'ai donc recréée 3 tables, comme me l'a suggéré mechkurt :

 


Table questions :

 

https://i.ibb.co/hyZg2Hw/table-q.jpg

 

Table réponses :

 

https://i.ibb.co/59f6dML/table-r.jpg

 

Table résultats :

 

https://i.ibb.co/G2xFqkG/table-resu.jpg

 


Actuellement :

 

La table question est remplie avec 14 questions.
La table réponse est remplie avec 75 reponses
La table résultat avec 4 entrées de test.

  

Je fais cette requête pour aller chercher dans la table "questions" l'id_question qui ne se trouve pas dans la table "resultats". Je me suis inspiré de ce site https://algocool.fr/types-jointures-sql/ pour les jointures.

 


$question  = $mysqli->query("select * from questions LEFT JOIN resultats ON questions.id_question = resultats.id_question WHERE questions.id_question IS NULL"

 

Pour afficher le résultat :

 

$j=0;
while ($row2 = $question->fetch_assoc())
{
echo $row2['id_question'];
         
$j++;
}

 

Dans ma table resultats j'ai comme id_questions : 1 2 3.
Normalement, avec la requête, je devrais avoir comme valeurs affichés tout sauf 1 2 3, soit : 4 5 6 7 etc jusqu'a 14 (les id_questions de ma table questions).

 

Or ca m'affiche 0.

 

Je viens de refaire un test en faisant "WHERE questions.id_question IS NOT NULL"

 

Ca m'affiche 1 2 3 comme id_question  de ma table resultats et non 4 5 6 7 .. de ma table questions


Message édité par La classe @ dallas le 08-12-2020 à 12:17:40

---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 08-12-2020 à 12:42:06    

Ca marche PRESQUE :D
 
J'ai pris cette requête :
 
$question  = $mysqli->query("SELECT * FROM questions LEFT JOIN resultats ON questions.id_question = resultats.id_question WHERE resultats.id_question IS NULL"
 
et au lieu de echo $row2['id_question']; j'ai mis echo $row2['question'];
 
Tous les bons libellés s'affichent !!
 
Bizarre, quand je mets echo $row2['id_question']; les id ne s'affichent pas par contre :/


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 08-12-2020 à 13:08:51    

Bon super, ca fonctionne.
 
Je suis allé récupérer la variable couple_qr qui me permet de faire la correspondance entre la question et les réponses associées.
 
Donc j'ai bien réussi à récupérer le libellé de la question avec son numéro. Ca me permettra d'aller chercher les réponses.
 
Merci pour votre aide et merci mechkurt


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 08-12-2020 à 13:10:34    

Encore une fois, pourquoi id_test est dans une table un int(1) et dans les 2 autres tables, un int(10) :??:


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 08-12-2020 à 14:09:01    

Pour tester tes jointure, je te conseille de tester en récupérant toutes les clefs de tes tables (et sur un nombre limité de possibilité sinon tu aura clef x clef ligne) et sans WHERE ni GROUP BY, en voyant tes données dans phpmyadmin je penses que tu comprendras mieux sur quoi il faut filtrer (ON ou WHERE) et sur quoi tu veux agréger (GROUP BY).


---------------
D3
Reply

Marsh Posté le 08-12-2020 à 15:08:35    

rufo a écrit :

Encore une fois, pourquoi id_test est dans une table un int(1) et dans les 2 autres tables, un int(10) :??:


J'ai repris des infos de l ancienne table, sans correction.
Je vais effectivement ajuster :jap:


Message édité par La classe @ dallas le 08-12-2020 à 15:08:45

---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Marsh Posté le 08-12-2020 à 15:09:27    

mechkurt a écrit :

Pour tester tes jointure, je te conseille de tester en récupérant toutes les clefs de tes tables (et sur un nombre limité de possibilité sinon tu aura clef x clef ligne) et sans WHERE ni GROUP BY, en voyant tes données dans phpmyadmin je penses que tu comprendras mieux sur quoi il faut filtrer (ON ou WHERE) et sur quoi tu veux agréger (GROUP BY).


Merci pour l'astuce :jap:


---------------
They see me postin', they hatin', alertin' and tryna catch me trollin' dirty
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed