login  Naam:   Wachtwoord: 
Registreer je!
 Forum

INNER JOIN

Offline Frank56 - 25/10/2014 11:18
Avatar van Frank56Nieuw lid Met de volgende sql-opdracht haal ik van 5 databases informatie op als er een overeenkomst is met nr2 in lijst.leer.

De resultaten verschijnen pas als alle tabellen gevuld zijn.

Nu wil ik dat de resultaten gelijk zichtbaar worden als 1 van de tabellen hav, nh, fh, dh al gevuld is.

Hoe doe ik dat?

Als ik van de laatste drie een LEFT JOIN maak, ben ik verplicht om eerst hav te vullen, maar ik wil ook de resultaten al zien als bijvoorbeeld fh gevuld is.


  1. SELECT ...
  2. FROM hav
  3. INNER JOIN lijst
  4. ON hav.nr2=lijst.leer
  5. INNER JOIN nh
  6. ON nh.nr2=lijst.leer
  7. INNER JOIN fh
  8. ON fh.nr2=lijst.leer
  9. INNER JOIN dh
  10. ON dh.nr2=lijst.leer

20 antwoorden

Gesponsorde links
Offline Thomas - 25/10/2014 15:16 (laatste wijziging 25/10/2014 15:30)
Avatar van Thomas Moderator Die nr2/lijst.leer is wel de "spil" in je query. Wat stelt deze kolom voor? Misschien verdient deze kolom wel zijn eigen tabel? Die tabel zou je dan als uitgangspunt kunnen nemen voor je LEFT JOIN query?

EDIT: waarom neem je de lijst-tabel niet als uitgangspunt?

Zoiets dus:
  1. SELECT ...
  2. FROM lijst
  3. LEFT JOIN hav ON (hav.nr2 = lijst.leer)
  4. LEFT JOIN nh ON (nh.nr2 = lijst.leer)
  5. LEFT JOIN fh ON (fh.nr2 = lijst.leer)
  6. LEFT JOIN dh ON (dh.nr2 = lijst.leer)

Veel hangt af van de betekenis van deze tabellen en kolommen. Vaak hebben tabellen en kolommen omschrijvende namen, zodat ze "zelf-documenterend" zijn, je kunt daarbij uit de kolom meestal al de betekenis afleiden.

nr2, hav, lijst, nh, fh en dh zeggen mij daarentegen niet zoveel.

Daarnaast kun je in MySQL, als je een specifiek tabeltype hiervoor gebruikt, verbanden tussen de tabellen verankeren zodat deze tabellen niet als los zand aan elkaar hangen. Je doet dit middels relaties waar je bepaalde condities aan kunt hangen (ook wel foreign keys genaamd). Deze relaties zorgen er tevens voor dat de informatie die je in de databaes invoert consistent moet zijn met de reeds aanwezige data, zodat het resultaat (nog steeds) een harmonieus en kloppend geheel is (dit wordt ook wel referentiële integriteit genoemd).

Veel hangt wel weer af van wat voor data je in je database zet. Als het voornamelijk gegevens van "administratieve aard" zijn, waarbij het belangrijk is dat onderlinge verbanden in acht worden genomen, zou ik zeker overwegen om tabellen op te zetten volgens dit tabeltype (InnoDB) en gebruik te maken van beperkende condities (foreign keys).

Om je vraag te kunnen beantwoorden zullen we op zijn minst moeten weten wat voor informatie de tabellen (globaal) bevatten, en (specifiek) de kolommen die je in je query gebruikt.

Misschien loont het zelfs de moeite om de data die je op wilt slaan (opnieuw?) te analyseren, en vervolgens tot een andere (en mogelijk betere) database-opzet te komen.

Hierbij moet je nooit uit het oog verliezen wat voor data dit is en wat voor vraagstukken je vervolgens je database wilt kunnen stellen, beide factoren bepalen namelijk de structuur. Het feit dat je nu tegen een vraagstuk aanloopt wat je niet direct kunt beantwoorden zou ook een (klein) alarmbel(letje) moeten doen rinkelen met de vraag "zit mijn database-structuur wel goed in elkaar?".

Overigens is het niet zo dat je bij elk vraagstuk wat je niet direct kunt beantwoorden dat je database direct een complete overhaul nodig heeft. Wat je niet met één query kunt beantwoorden, kun je misschien met meerdere? Je zou het verkrijgen van het gewenste resultaat ook deels kunnen verplaatsen naar PHP en daar je resultaat (verder) opbouwen naar aanleiding van een of meer queries.

Je database zou wel een beetje slim in elkaar moeten zitten, want dit vormt doorgaans het fundament van je applicatie.
Offline Frank56 - 25/10/2014 21:05 (laatste wijziging 25/10/2014 22:31)
Avatar van Frank56 Nieuw lid 'Lijst' is een aparte tabel met gebruikers, maar als ik die als uitgangspunt neem en daar alleen LEFT JOIN op toepas, worden er meer dan 1000 gegevens geprint die ik niet nodig heb. Aan de andere kant kost het te veel tijd om 'lijst' steeds voor de doelgroep aan te passen.

'nr2' is een nummer die ook in 'lijst' staat. hav, nh etc. verwijzen naar de tabellen waar de in te vullen items staan. Met nr2 en lijst.leer combineer ik de juiste items met de gebruikers.

De foreign keys zijn nieuw voor mij. Ik heb jullie tuturial erover gelezen, maar ik denk dat ik dit al doe, omdat ik de waardes 'nr2' en 'lijst.leer' al identiek laat zijn en daarmee een relatie tussen de twee tabellen aangeef.

Ik begrijp niet hoe je verschillende query's in PHP moet opbouwen en dan weer samenvoegen, zodat alle databases een relatie hebben met 'lijst' en toch onafhankelijk van elkaar in een tabel verschijnen, wanneer ze gemaakt zijn. Kun je me een hint geven hoe ik dat moet doen?





  1. <?php
  2.  
  3. function bepaalKleurInterval($color) {
  4. if (-10 <= $color && $color < 2) {
  5. $kleur = '#DF0101'; // rood
  6. } elseif (2 <= $color && $color < 5.5) {
  7. $kleur = '#F7D358'; // oranje
  8. } elseif (5.5 <= $color && $color < 8) {
  9. $kleur = '#31B404'; // geel
  10. } elseif (8 <= $color && $color < 10) {
  11. $kleur = '#31B404'; // groen
  12. } elseif ($color == 10) {
  13. $kleur = '#31B404'; // groen
  14. } else {
  15. $kleur = 'white'; // onbekende waarde wit
  16. }
  17. return $kleur;
  18. }
  19.  
  20. function formatteerGetal($invoer) {
  21. if ($invoer < 1) {
  22. return 1;
  23. } else {
  24. return $invoer;
  25. }
  26. }
  27.  
  28.  
  29.  
  30.  
  31.  
  32. $query = "SELECT *,
  33.  
  34. ROUND((((regelk1+regelk2+regelk3+regelk4)*18)/4)-8,1) AS nehar,
  35.  
  36. ROUND((((wwspel1+wwspel2+wwspel3+wwspel4+overigew1+overigew2+overigew3+overigew4+interp1+interp2+interp3+interp4+taalkundigontl1+taalkundigontl2+taalkundigontl3+taalkundigontl4+redekundigontl1+redekundigontl2+redekundigontl3+redekundigontl4)*18)/20)-8,1) AS nehat1,
  37.  
  38.  
  39. ROUND((((life1+life2+life3+life4+life5+life6+life7+life8+food1+food2+food3+food4+food5+food6+food7+food8+food9+food10+key1+key2+key3+key4+key5+key6+key7+key8)*18)/26)-8,1) AS enhat1,
  40.  
  41. ROUND((((jean1+jean2+jean3+jean4+jean5+jean6+jean7+jean8+jean9)*18)/9)-8,1) AS fahat1,
  42.  
  43. ROUND((((ww1+ww2+ww3+ww4+ww5+ww6+ww7+naamv1+naamv2+naamv3+naamv4+naamv5+naamv6+woordb1+woordb2+woordb3+woordb4+woordb5+woordb6+video1+video2+tekst1+tekst2+tekst3+tekst4)*18)/25)-8,1) AS duhat1,
  44.  
  45. ROUND((((formul1+formul2+formul3+formul4)*9)/4)+1,1) AS nehat2,
  46.  
  47. ROUND((((concerns1+concerns2+concerns3+concerns4+concerns5+concerns6+concerns7+concerns8+concerns9+concerns10+concerns11+concerns12+exam1+exam2+exam3+exam4+exam5+exam6+exam7+exam8+exam9+exam10+exam11+exam12+folk1+folk2+folk3+folk4+folk5+folk6+folk7+folk8+folk9+folk10+folk11+folk12+folk13+folk14+folk15)*9)/39)+1,1) AS enhat2,
  48.  
  49. ROUND((((prets1+prets2+prets3+prets4+prets5+prets6+courir1)*9)/7)+1,1) AS fahat2,
  50.  
  51. ROUND((((past1+past2+past3+past4+woordb7+woordb8)*9)/6)+1,1) AS duhat2,
  52.  
  53. ROUND((((tekstbegrip1+tekstbegrip2+tekstbegrip3)*9)/3)+1,1) AS nehai,
  54.  
  55.  
  56.  
  57. ROUND((((((regelk1+regelk2+regelk3+regelk4)*18)/4)-8)+((((wwspel1+wwspel2+wwspel3+wwspel4+overigew1+overigew2+overigew3+overigew4+interp1+interp2+interp3+interp4+taalkundigontl1+taalkundigontl2+taalkundigontl3+taalkundigontl4+redekundigontl1+redekundigontl2+redekundigontl3+redekundigontl4)*18)/20)-8)+(((formul1+formul2+formul3+formul4)*9/4)+1)+((((tekstbegrip1+tekstbegrip2+tekstbegrip3)*9)/3)+1))/4,1) AS cijferne,
  58.  
  59.  
  60. ROUND((((((life1+life2+life3+life4+life5+life6+life7+life8+food1+food2+food3+food4+food5+food6+food7+food8+food9+food10+key1+key2+key3+key4+key5+key6+key7+key8)*18)/26)-8)+((((concerns1+concerns2+concerns3+concerns4+concerns5+concerns6+concerns7+concerns8+concerns9+concerns10+concerns11+concerns12+exam1+exam2+exam3+exam4+exam5+exam6+exam7+exam8+exam9+exam10+exam11+exam12+folk1+folk2+folk3+folk4+folk5+folk6+folk7+folk8+folk9+folk10+folk11+folk12+folk13+folk14+folk15)*9)/39)+1))/2,1) AS cijferen,
  61.  
  62.  
  63. ROUND((((((jean1+jean2+jean3+jean4+jean5+jean6+jean7+jean8+jean9)*18)/9)-8)+((((prets1+prets2+prets3+prets4+prets5+prets6+courir1)*9)/7)+1))/2,1) AS cijferfa,
  64.  
  65.  
  66.  
  67.  
  68. ROUND((((((ww1+ww2+ww3+ww4+ww5+ww6+ww7+naamv1+naamv2+naamv3+naamv4+naamv5+naamv6+woordb1+woordb2+woordb3+woordb4+woordb5+woordb6+video1+video2+tekst1+tekst2+tekst3+tekst4)*18)/25)-8)+((((past1+past2+past3+past4+woordb7+woordb8)*9)/6)+1))/2,1) AS cijferdu,
  69.  
  70. regelk1+regelk2+regelk3+regelk4+wwspel1+wwspel2+wwspel3+wwspel4+overigew1+overigew2+overigew3+overigew4+interp1+interp2+interp3+interp4+taalkundigontl1+taalkundigontl2+taalkundigontl3+taalkundigontl4+redekundigontl1+redekundigontl2+redekundigontl3+redekundigontl4+formul1+formul2+formul3+formul4+tekstbegrip1+tekstbegrip2+tekstbegrip3 AS totaal
  71.  
  72. FROM hav
  73. INNER JOIN lijst
  74. ON hav.nr2=lijst.leer
  75. INNER JOIN nh
  76. ON nh.nr2=lijst.leer
  77. LEFT JOIN fh
  78. ON fh.nr2=lijst.leer
  79. LEFT JOIN dh
  80. ON dh.nr2=lijst.leer
  81.  
  82. ORDER BY klas ASC ";
  83.  
  84.  
  85. // de SQL-query die wordt uitgevoerd
  86. $resultaat = mysql_query($query, $db);
  87.  
  88. echo "<h2></h2><p>\n";
  89. echo "\n";
  90.  
  91. while( $row = mysql_fetch_assoc($resultaat) )
  92. {
  93.  
  94. ?>
  95.  
  96. <center>
  97. <table border=0 width="500" height="50" cellspacing=5 cellpadding=5 bgcolor=white >
  98.  
  99.  
  100. <tr>
  101. <tr><td colspan=3><b><?php echo $row['naam']; ?></b></td><td colspan=1><?php echo $row['klas']; ?></td></tr>
  102. </tr>
  103.  
  104. <tr>
  105. <th>Ne R</th><th>En R</th><th>Fa R</th><th>Du R</th>
  106. </tr>
  107.  
  108. <?php $eindNehar = round(formatteerGetal($row['nehar']),1);?>
  109.  
  110.  
  111.  
  112. <tr>
  113. <td style="background-color: <?php echo bepaalKleurInterval($eindNehar) ?>;"><?php echo $eindNehar ?></td>
  114.  
  115. </tr>
  116. <tr>
  117. <th>Ne T1</th><th>En T1</th><th>Fa T1</th><th>Du T1</th>
  118. </tr>
  119.  
  120. <?php $eindNehat1 = round(formatteerGetal($row['nehat1']),1);?>
  121. <?php $eindEnhat1 = round(formatteerGetal($row['enhat1']),1);?>
  122. <?php $eindFahat1 = round(formatteerGetal($row['fahat1']),1);?>
  123. <?php $eindDuhat1 = round(formatteerGetal($row['duhat1']),1);?>
  124.  
  125.  
  126.  
  127.  
  128. <tr>
  129. <td style="background-color: <?php echo bepaalKleurInterval($eindNehat1) ?>;"><?php echo $eindNehat1 ?></td>
  130. <td style="background-color: <?php echo bepaalKleurInterval($eindEnhat1) ?>;"><?php echo $eindEnhat1 ?></td>
  131. <td style="background-color: <?php echo bepaalKleurInterval($eindFahat1) ?>;"><?php echo $eindFahat1 ?></td>
  132. <td style="background-color: <?php echo bepaalKleurInterval($eindDuhat1) ?>;"><?php echo $eindDuhat1 ?></td>
  133. </tr>
  134. <tr>
  135. <th>Ne T2</th><th>En T2</th><th>Fa T2</th><th>Du T2</th>
  136. </tr>
  137.  
  138.  
  139. <?php $eindNehat2 = round(formatteerGetal($row['nehat2']),1);?>
  140. <?php $eindEnhat2 = round(formatteerGetal($row['enhat2']),1);?>
  141. <?php $eindFahat2 = round(formatteerGetal($row['fahat2']),1);?>
  142. <?php $eindDuhat2 = round(formatteerGetal($row['duhat2']),1);?>
  143.  
  144.  
  145.  
  146. <tr>
  147. <td style="background-color: <?php echo bepaalKleurInterval($eindNehat2) ?>;"><?php echo $eindNehat2 ?></td>
  148. <td style="background-color: <?php echo bepaalKleurInterval($eindEnhat2) ?>;"><?php echo $eindEnhat2 ?></td>
  149. <td style="background-color: <?php echo bepaalKleurInterval($eindFahat2) ?>;"><?php echo $eindFahat2 ?></td>
  150. <td style="background-color: <?php echo bepaalKleurInterval($eindDuhat2) ?>;"><?php echo $eindDuhat2 ?></td>
  151. </tr>
  152. <tr>
  153. <th>Ne I</th><th>En I</th><th>Fa I</th><th>Du I</th>
  154.  
  155. <?php $eindNehai = round(formatteerGetal($row['nehai']),1);?>
  156.  
  157.  
  158. </tr>
  159. <tr>
  160. <td style="background-color: <?php echo bepaalKleurInterval($eindNehai) ?>;"><?php echo $eindNehai ?></td>
  161. </tr>
  162.  
  163. <?php $eindCijferne = round((formatteerGetal($row['nehar']) + formatteerGetal($row['nehat1'])+ formatteerGetal($row['nehat2']) + formatteerGetal($row['nehai']))/4,1);?>
  164. <?php $eindCijferen = round((formatteerGetal($row['enhat1'])+ formatteerGetal($row['enhat2']))/2,1);?>
  165. <?php $eindCijferfa = round((formatteerGetal($row['fahat1'])+ formatteerGetal($row['fahat2']))/2,1);?>
  166. <?php $eindCijferdu = round((formatteerGetal($row['duhat1'])+ formatteerGetal($row['duhat2']))/2,1);?>
  167.  
  168.  
  169. <tr>
  170. <th>Ne gem.</th><th>En gem.</th><th>Fa gem.</th><th>Du gem.</th>
  171. </tr>
  172. <tr>
  173. <td style="background-color: <?php echo bepaalKleurInterval($eindCijferne) ?>;"><?php echo $eindCijferne ?></td>
  174. <td style="background-color: <?php echo bepaalKleurInterval($eindCijferen) ?>;"><?php echo $eindCijferen ?></td>
  175. <td style="background-color: <?php echo bepaalKleurInterval($eindCijferfa) ?>;"><?php echo $eindCijferfa ?></td>
  176. <td style="background-color: <?php echo bepaalKleurInterval($eindCijferdu) ?>;"><?php echo $eindCijferdu ?></td></tr>
  177.  
  178.  
  179. </table>
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188. <br><br><br>
  189.  
  190.  
  191. <?
  192. }
  193. }
  194. }
  195. }
  196. ?>
Offline Thomas - 25/10/2014 23:13
Avatar van Thomas Moderator
Frank56 schreef:
'Lijst' is een aparte tabel met gebruikers, maar als ik die als uitgangspunt neem en daar alleen LEFT JOIN op toepas, worden er meer dan 1000 gegevens geprint die ik niet nodig heb.
Maar als er een niet-NULL resultaat is in een van de kolommen van de tabellen (hav, nh, fh, dh) dan is dat resultaat toch relevant, zoveel vraag je volgens mij in je oorspronkelijke bericht:
Frank56 schreef:
Als ik van de laatste drie een LEFT JOIN maak, ben ik verplicht om eerst hav te vullen, maar ik wil ook de resultaten al zien als bijvoorbeeld fh gevuld is.
En de resultaten die enkel NULL-waarden bevatten (en dus niet interessant zijn waarschijnlijk) kun je er al uitfilteren met WHERE-condities! Dan heb je toch precies de informatie die je wilt?

Frank56 schreef:
Aan de andere kant kost het te veel tijd om 'lijst' steeds voor de doelgroep aan te passen.
Wat is de doelgroep? Is dit een eigenschap die in een van de kolommen van een tabel is opgeslagen? Die kun je dan als argument in je query opnemen om resultaten te filteren.

Mits je tabelstructuur handig in elkaar zit kan MySQL je gegevens meestal direct ophalen.

Frank56 schreef:
De foreign keys zijn nieuw voor mij. Ik heb jullie tuturial erover gelezen, maar ik denk dat ik dit al doe, omdat ik de waardes 'nr2' en 'lijst.leer' al identiek laat zijn en daarmee een relatie tussen de twee tabellen aangeef.
Enkel omdat de kolomtypes en de waarden van twee kolommen uit twee verschillende tabellen overeenkomen, wil dat nog niet zeggen dat MySQL deze als zodanig (identiek) herkent. Daarbij sputtert MySQL niet tegen als je in een van de twee kolommen een waarde wijzigt, verwijdert of toevoegt waardoor mogelijk een inconsistent geheel zou kunnen ontstaan. Met andere woorden, de tabellen hangen, indien er nog steeds geen gebruik wordt gemaakt van foreign keys, als los zand aan elkaar. Nu is dat voor je huidige probleem niet erg, maar ja, ik weet niet of het verstandig is.

Frank56 schreef:
Ik begrijp niet hoe je verschillende query's in PHP moet opbouwen en dan weer samenvoegen, zodat alle databases een relatie hebben met 'lijst' en toch onafhankelijk van elkaar in een tabel verschijnen, wanneer ze gemaakt zijn. Kun je me een hint geven hoe ik dat moet doen?
Dat wordt voor mij een beetje een lastige opgave omdat ik geen idee heb wat al die tabellen/kolommen betekenen. Wat je in PHP zou kunnen doen is "datastructuren" bouwen met behulp van arrays - hierin sla je je opgehaalde gegevens op een gestructureerde manier op zodat je er daarna, als je alle gegevens, mogelijk uit meerdere queries, verzameld hebt, makkelijk mee kunt rekenen. Je hevelt daarmee dus een deel van het rekenwerk over naar PHP en MySQL (de queries) gebruik je meer voor het selecteren van de juiste data (maar voer je nog geen berekeningen uit omdat je dit bijvoorbeeld nog niet kunt omdat je nog niet alle informatie verzameld hebt).

Misschien is het slechts een kwestie van wat WHERE-condities toevoegen (zie begin van dit relaas), anders zul je meer uitleg moeten geven over de tabellen, kolommen, de data daarin en de betekenis van dat alles. Daarna kun je waarschijnlijk ook beter uitleggen wat je uiteindelijk probeert te bereiken. Een scherpe(re) probleemformulering kan (enorm) helpen bij het oplossen ervan.
Offline Frank56 - 07/11/2014 11:34 (laatste wijziging 07/11/2014 11:57)
Avatar van Frank56 Nieuw lid Hierbij voeg ik alle codes. Hopelijk wordt het dan duidelijker.

Scheelt het overhevelen van het rekenwerk naar PHP en MySQL geheugen?

Het systeem is met meer dan 200 gebruikers na 35 minuten namelijk wegens gebrek aan geheugen 'geklapt'.

Kan ik niet tegelijkertijd gebruikers werk laten opslaan, terwijl andere gebruikers de inhoud van de database bekijken?

Zijn er handelingen die hetzelfde resultaat opleveren als ze efficiënter geprogrammeerd worden?

Plaatscode: 142388
Plaatscode: 142389
Plaatscode: 142390
Plaatscode: 142391
Plaatscode: 142392
Plaatscode: 142393
Plaatscode: 142394
Plaatscode: 142395
Plaatscode: 142396
Plaatscode: 142397
Plaatscode: 142398
Plaatscode: 142399
Plaatscode: 142400
Plaatscode: 142401
Offline Thomas - 07/11/2014 17:45
Avatar van Thomas Moderator De laatste vier plaatscode links (142398 t/m 142401) bevatten tabeldefinities van tabellen (t0401arg(kopie), t0401form(kopie), t0401spel(kopie), t0401woord(kopie)) die niet terugkomen in jouw bovenstaande code.

Echter, als de opzet van deze tabellen representatief is voor de rest van je database (en ook de tabellen hav, lijst, nh, fh, dh en klas) dan heb ik al een aardig idee wat er aan de hand is.

Het komt eigenlijk allemaal op het volgende neer: de tabellen zijn op geen enkele manier geoptimaliseerd. Kan het kloppen dat deze tabellen 1:1 zijn overgezet van spreadsheets?

Ik zal proberen wat pointers te geven, maar ik vrees dat je terug naar de tekentafel zult moeten hiermee.

* je tabellen hebben behalve je primaire sleutel (die verder geen enkel doel dient?) geen enkele vorm van indexe(ri)n(g); indexering zorgt ervoor dat je records snel kunt opzoeken als je op zo'n kolom zoekt in een tabel, en ook (en nog belangrijker) als je informatie van verschillende tabellen wilt combineren; dat gaat echter in jouw geval niet werken, want je gebruikt het MyISAM tabeltype; wanneer je data van "administratieve aard" hebt (waarbij onderlingen tabelverbanden belangrijk zijn), dan loont het de moeite om van het InnoDB tabeltype gebruik te maken; dit type ondersteunt namelijk FOREIGN KEYS (de manier om tabellen op een efficiente manier aan elkaar te lijmen), MyISAM niet tenzij je MySQL versie 5.6 of nieuwer gebruikt

* je kolommen zijn alle TEXT of VARCHAR? Zelfs als je leerlingnummer(2) geen nummer is, loont het de moeite om gegevens van leerlingen in een aparte tabel bij te houden en vervolgens via een intern nummer aan een leerling te refereren. Daarnaast: je t0401spel(kopie) tabel bevat 36 TEXT kolommen (sp1 t/m sp36). Wat voor data zit hierin? Cijfers? Of ook tekst? Daarnaast: zijn al deze kolommen altijd gevuld of is dit om "voldoende invulvakjes" te hebben om je data kwijt te kunnen?

* als ik je bovenstaande reactie bekijk, dan kan er nog iets veel vervelenders gebeuren dan inefficiënte opslag: corrumpering van je data; als meerdere gebruikers "tegelijkertijd" dezelfde data wijzigen kunnen er vervelende dingen gebeuren als je hier geen speciale voorzieningen voor treft; alle operaties die je DATA veranderen moeten ondeelbare (atomaire) acties zijn, anders is de kans aanwezig dat je data op den duur niet meer consistent is. Nu hangt dit natuurlijk af van je code, je database etc, maar voorkomen lijkt mij beter dan genezen... Als je (zware) administratieve systemem gebruikt waarbij het heel belangrijk is dat je informatie kloppend is en kloppend blijft, dan zou ik zeker overwegen om gebruik te maken van transacties... en dit is weer een functionaliteit die NIET ondersteund wordt door MyISAM, wel door InnoDB.

Overigens ben ik niet echt wijzer geworden uit bovenstaande code fragmenten en database dumps, ik zie niet welke data er in zit, maar wel hoe deze mogelijk mishandeld wordt...

Dan antwoord op je vragen:
Citaat:
Scheelt het overhevelen van het rekenwerk naar PHP en MySQL geheugen?
Dat kan verschillen. Je bent in eerste instantie (veel meer / ) beter gediend met een efficient database-ontwerp. En daar is, als ik de voorbeeld-dumps als leidraad moet nemen, geenszins sprake van.

Citaat:
Het systeem is met meer dan 200 gebruikers na 35 minuten namelijk wegens gebrek aan geheugen 'geklapt'.
Als je in hoog tempo veel zware/inefficiente queries uitvoert kan ik mij daar iets bij voorstellen. Daarnaast moet je hardware hier ook op zekere hoogte bestand tegen zijn. Dit is geen 1-dimensionaal probleem, maar je bent zeker je eigen ruiten aan het ingooien als je (makkelijke) efficiency-winst niet meepakt.

Citaat:
Kan ik niet tegelijkertijd gebruikers werk laten opslaan, terwijl andere gebruikers de inhoud van de database bekijken?
Ja, mits je hier voorzieningen voor treft (InnoDB, effificient ontwerp, transacties).

Citaat:
Zijn er handelingen die hetzelfde resultaat opleveren als ze efficiënter geprogrammeerd worden?
Die zijn er altijd, en meestal leveren ze ook sneller deze resultaten op . Maar in dit geval zijn er geen eenvoudige kunstgrepen die je kunt toepassen om dit allemaal in 1x op te lossen vrees ik, als je dat bedoelt.

Geef voor de gein eens voorbeelden van DATA van een of enkele (desnoods geanonimiseerde) records van alle eerdergenoemde tabellen? Ik had volgens mij eerder ook al een idee voor het opslaan van toetsresultaten als gehele getallen, maar ja als alles TEXT is ... 
Offline Frank56 - 11/11/2014 19:53 (laatste wijziging 11/11/2014 19:54)
Avatar van Frank56 Nieuw lid Hierbij voeg ik gevulde tabellen, zodat je kunt zien welke data ingevoerd wordt.

Plaatscode: 142403
Plaatscode: 142404
Plaatscode: 142405
Plaatscode: 142406

In de php-bestanden verwijs ik naar:

  1. <meta http-equiv="content-type" content="text/html; charset=UTF-8" />


Kan ik dan in de tabellen afwisselend kolommen opnemen met int en met utf8_general_ci?

Ik gebruik de volgende versie van PHPMyAdmin: Serverversie: 5.5.40-MariaDB - MariaDB Server. Kan ik daarin FOREIGN KEYS gebruiken?

Ik zie niet hoe ik hier InnoDB tabeltype kan kiezen, hoewel ik in engine opslag zowel MRG_MYISAM als InnoDB Percona-XtraDB, Supports transactions, row-level locking, and foreign keys zie staan. Waar kan ik dit kiezen?

Kun je een tip geven voor een host die dit programma probleemloos kan hosten, wanneer de tabellen geoptimaliseerd zijn?
Offline Thomas - 11/11/2014 21:16
Avatar van Thomas Moderator
Citaat:
Kan ik dan in de tabellen afwisselend kolommen opnemen met int en met utf8_general_ci?
Je haalt hier weer een aantal dingen door elkaar. Ik heb je al uitgelegd wat het verschil is tussen character encoding en character collation.

Het probleem is je structuur, niet je encoding. Je tabellen bevatten enkel kolommen van het type text en hebben geen relaties met andere tabellen (mede vanwege je tabeltype) en daardoor ook geen snelle lookup. Als je vervolgens grote tabellen aan elkaar knoopt in queries wordt e.e.a. enorm traag. Ik heb je in andere topics al een heleboel tips gegeven: begin bij het einde: welke vraagstukken wil je beantwoord zien met queries. Mede op grond hiervan modelleer je je database(-tabellen).

Uit de summiere tabellen dumps kan ik weinig afleiden. Bevatten alle kolommen getallen? Waarom gebruik je dan geen INT(EGER) als kolomtype? Uit hoeveel records bestaan de tabellen, hoeveel tabellen hebben we het over? Wat betekenen de kolommen? Deze vragen heb ik al eerder gesteld. Als je niets omschrijft kan ik je niet helpen...

Citaat:
Ik gebruik de volgende versie van PHPMyAdmin: Serverversie: 5.5.40-MariaDB - MariaDB Server. Kan ik daarin FOREIGN KEYS gebruiken?
InnoDB bestaat al een hele tijd, dus tenzij je database uit het stenen tijdperk komt... Daarnaast kun je dit natuurlijk ook eenvoudig uitproberen door een of meer tabellen aan te maken...

Citaat:
Ik zie niet hoe ik hier InnoDB tabeltype kan kiezen, hoewel ik in engine opslag zowel MRG_MYISAM als InnoDB Percona-XtraDB, Supports transactions, row-level locking, and foreign keys zie staan. Waar kan ik dit kiezen?
tweede google resultaat (google zoekopdracht "phpmyadmin choosing innodb table type"). Heb je hier zelf uberhaupt op gezocht?

Citaat:
Kun je een tip geven voor een host die dit programma probleemloos kan hosten, wanneer de tabellen geoptimaliseerd zijn?
Nee, ik beweeg mij nauwelijks in de hosting wereld.

Ik zie eerlijk gezegd niet goed hoe ik je verder kan helpen, behalve dat ik je adviseer je wat meer in de MySQL materie te verdiepen zodat je onderbouwde keuzes kunt maken bij het opstellen van een efficient(er) database-ontwerp.
Offline Frank56 - 12/11/2014 06:00
Avatar van Frank56 Nieuw lid Dank je wel.

De tabellen zijn inderdaad InnoDB.

In elke van de vier tabellen zitten meer dan 200 records.

In de tabellen die ik heb laten zien zijn niet meer dan 20 kolommen, maar ik gebruik ook regelmatig tabellen met 75 kolommen. Is dat te veel?

Elke kolom geeft het antwoord op een vraag die beoordeeld wordt met 1 of 0, maar er zijn ook kolommen bij waarin een tekst komt te staan.

De kolommen worden verbonden met leerlingnummer2. Dat is het unieke nummer dat weer via query's verbonden wordt met een andere tabel waarin meer gegevens staan per leerlingnummer2. Moet ik hier de primary key van maken? De primary key die ik nu heb, gebruik ik inderdaad niet, dus die kan weg.

Ik zie niet hoe ik dit verder kan normaliseren.

Volgens mij komt het probleem daarna, als ik de gemiddelden op het scherm laat zien van alle resultaten van alle tabellen van de 200 leerlingnummer2. Als ik dat tegelijkertijd laat doen met het invullen van de vier tabellen arg, form, spel en woord loopt het systeem vast. Ik vraag me af hoe ik dit kan normaliseren, zodat het goed verloopt of kan ik deze stap beter laten uitvoeren als alle gegevens al in de vier tabellen staan?
Offline Thomas - 12/11/2014 15:17
Avatar van Thomas Moderator
Citaat:
De tabellen zijn inderdaad InnoDB.
Ik zie bij de code-dumps in je voorlaatste bericht bij elk van de tabellen ENGINE=MyISAM staan. Betekent dit dat je de tabellen hebt omgezet naar InnoDB? Het omzetten alleen is natuurlijk niet genoeg, maar je hebt nu meer voorzieningen tot je beschikking.
Citaat:
In de tabellen die ik heb laten zien zijn niet meer dan 20 kolommen, maar ik gebruik ook regelmatig tabellen met 75 kolommen. Is dat te veel?
Hmm, als die kolommen allemaal min of meer dezelfde rol vervullen, loont het misschien de moeite om hier een (of meer) aparte tabellen van te maken? Een database kan te "breed" worden (teveel tabellen) maar ook te "diep" (teveel kolommen per tabel).
Citaat:
Elke kolom geeft het antwoord op een vraag die beoordeeld wordt met 1 of 0, maar er zijn ook kolommen bij waarin een tekst komt te staan.

Aha, en de tekst is ook de antwoord op een vraag (en zoja, hoe beoordeel je of deze goed is?), of iets anders? En telt deze nog op een of andere manier mee in de berekening van het "eindcijfer"? Elk record van zo'n tabel vormen dus de toetsresultaten van zo'n leerling? Wegen alle vragen even zwaar (altijd maximale score 1), of kunnen deze ook een ander gewicht hebben?

Een mogelijk andere aanpak is bijvoorbeeld: je zou een tabel "toetsen" aan kunnen maken (met alle (meta)data omtrent een toets), een tabel "toets_vragen" (met hierin alle informatie omtrent een toetsvraag (bijvoorbeeld type: text of score en het "gewicht" van een vraag)) en een tabel "toets_antwoorden" (met hierin de antwoorden die een specifieke leerling bij een specifieke toets heeft gegeven). Er zijn eindeloos veel varianten mogelijk. Het uitrekenen van een gemiddelde wordt dan volgens mij wat eenvoudiger (je kunt dan gebruik maken van SUM en COUNT). Daarnaast helpt het wellicht ook dat deze "antwoorden" tabel enkel uit numerieke kolommen bestaat, volgens mij kon er dan een extra optimalisatie plaatsvinden maar ik heb hier geen bewijs voor / voorbeeld van, dit staat mij bij uit een vaag ver verleden.
Citaat:
De kolommen worden verbonden met leerlingnummer2. Dat is het unieke nummer dat weer via query's verbonden wordt met een andere tabel waarin meer gegevens staan per leerlingnummer2. Moet ik hier de primary key van maken?
leerlingnummer2 is alleen primary key in de leerlingen tabel. In alle andere tabellen is dit een FOREIGN key, die verwijst naar de leerlingen-tabel.
Citaat:
De primary key die ik nu heb, gebruik ik inderdaad niet, dus die kan weg.
In zekere zin heeft een primary key (of liever gezegd een AUTO_INCREMENT veld) altijd een bestaansrecht in een tabel, al was het maar om het record uniek te identificeren. Een uitzondering op deze regel is misschien een koppeltabel, waarin je een relatie aangeeft tussen twee of meer andere tabellen, je hoeft hier geen extra auto_increment veld aan toe te voegen als deze tabel enkel uit foreign keys bestaat. Een uitzondering hier weer op is dat dat misschien wel de moeite loont als je meer "metadata" aan je koppeltabel hangt (ik kan zo gauw even geen voorbeeld verzinnen).
Citaat:
Ik zie niet hoe ik dit verder kan normaliseren.
Ik ook niet (als ik kijk naar de huidige tabellen). Maar beschrijf de data waarmee je werkt eens in objecten / mensentaal (toetsen, leerlingen, vragen, antwoorden). Wellicht hebben sommige van die kenmerken wel een bestaansrecht als tabel of kolom.
Citaat:
Volgens mij komt het probleem daarna, als ik de gemiddelden op het scherm laat zien van alle resultaten van alle tabellen van de 200 leerlingnummer2. Als ik dat tegelijkertijd laat doen met het invullen van de vier tabellen arg, form, spel en woord loopt het systeem vast. Ik vraag me af hoe ik dit kan normaliseren, zodat het goed verloopt of kan ik deze stap beter laten uitvoeren als alle gegevens al in de vier tabellen staan?
De vraag is ook een beetje: waarom zou je al die informatie tegelijkertijd op je scherm willen zien? Nog terwijl deze incompleet is (bij het invullen ervan)?

Ik denk dat je het meeste gebaat bent met een (korte) herbezinning van hoe je je data wilt structureren. Ik gebruik normalisatie nooit (bewust),dit was toch een standaard recept voor de vorming van je tabellen en kolommen? Het probleem daarvan is een beetje dat het geen rekening houdt met de aard van je data en de vraagstukken (queries) die je er op uit wilt voeren. Als je de standaard normalisatie-route volgt dan kun je uiteindelijk uitkomen in een situatie waarbij je databasetabel perfect genormaliseerd is, maar compleet onbruikbaar om je data er weer uit te halen . Misschien is het in jouw geval zelfs een idee om redundante (tussen)resultaten op te slaan (als het gedrag van je data dit toestaat, bijvoorbeeld omdat deze na invoeren niet meer wijzigen) om berekeningen sneller te kunnen uitvoeren. Dit soort beslissingen hangen helemaal van de aard van je data en het toepassingsgebied af (en hoe deze data zich verder ontwikkelt / uitbreidt in de toekomst, dat moet je ook niet vergeten).

Het is volgens mij redelijk duidelijk dat dat in de huidige opzet niet (goed) gaat werken, maar het heeft geen zin om deze opzet dan verder te analyseren want ik denk dat je al hebt besloten dat deze opzet moet veranderen . Alle verdere analyse van deze huidge opzet is daarmee overbodig geworden .
Offline Frank56 - 12/11/2014 20:24
Avatar van Frank56 Nieuw lid Dank je wel.

Het is voor mij duidelijk dat ik alle tabellen ga herzien.

Met het gebruik van de FOREIGN KEY stuit ik op een probleem.

In de tabel leerlingnummer staan in de kolom leerlingnummer2 unieke nummers die niet overschreven mogen worden. Als ik de PRIMARY KEY erop zet, blijven de unieke nummers wel gehandhaafd, de sleutel wordt grijs, maar AUTO_INCREAMENT wordt niet ingeschakeld. Is dat een bezwaar voor het goed functioneren van de FOREIGN KEYS met de PRIMARY KEY?

Ik kan er in de tabel leerlingnummer natuurlijk wel een kolom PRIMARY KEY naast zetten en van de kolom leerlingnummer2 in de tabel leerlingnummer een FOREIGN KEY maken, maar dan vraag ik me af of deze werkwijze minder vertragend is dan de oplossing zonder FOREIGN KEY. Is hier nog een andere oplossing voor?
Offline Thomas - 13/11/2014 15:30 (laatste wijziging 13/11/2014 15:35)
Avatar van Thomas Moderator
Citaat:
In de tabel leerlingnummer staan in de kolom leerlingnummer2 unieke nummers die niet overschreven mogen worden. Als ik de PRIMARY KEY erop zet, blijven de unieke nummers wel gehandhaafd, de sleutel wordt grijs, maar AUTO_INCREAMENT wordt niet ingeschakeld. Is dat een bezwaar voor het goed functioneren van de FOREIGN KEYS met de PRIMARY KEY?
Dat lijkt mij geen bezwaar. Je zou er ook voor kunnen kiezen om een auto_increment primary key op je leerlingen-tabel te zetten die als interne referentie dient, en het leerlingnummer2 als aparte (unieke) kolom in deze tabel opnemen (dit is dan je externe referentie, optioneel met een index, als je vaak op leerlingnummer zoekt). Het is dan wel zaak dat je de "relatie" primary key - leerlingnummer2 in stand houdt in je leerlingentabel en andere data aan dit interne nummer knoopt, met inachtneming dat deze informatie bij leerlingnummer XYZ hoort. Wellicht is jouw oplossing (leerlingnummer2 als primary key zonder AI) initieel beter, en zeker eenvoudiger.
Citaat:
Ik kan er in de tabel leerlingnummer natuurlijk wel een kolom PRIMARY KEY naast zetten en van de kolom leerlingnummer2 in de tabel leerlingnummer een FOREIGN KEY maken, maar dan vraag ik me af of deze werkwijze minder vertragend is dan de oplossing zonder FOREIGN KEY. Is hier nog een andere oplossing voor?
Als ik het goed begrijp wil je een foreign key laten verwijzen naar de leerlingnummer2-kolom in de leerlingen-tabel, ondanks het feit dat deze geen primary key is? Die werkwijze komt mij niet heel bekend over. Je zou dan op zijn minst (als dit uberhaupt gaat werken) een INDEX (en UNIQUE constraint) op deze kolom aan moeten leggen. Die krijg je al cadeau met je primary key. Daarnaast is het misschien ook een beter idee om de scheiding tussen "externe unieke nummers" en "interne unieke nummers" zo duidelijk mogelijk te laten zijn, m.a.w., te beperken tot je leerlingen-tabel. Daarmee creeer je miscshien wel wat overhead zoals hierboven al beschreven staat. Er zijn zowel voor- als nadelen om dit soort externe referenties te hardcoden door je hele systeem, maar voor wat jij er mee wilt doen maakt het waarschijnlijk niet uit.

Ik heb dit geprobeerd (het aanmaken van een FK die verwijst naar een kolom in een andere tabel die geen PK is) en het schijnt te werken, maar dit lijkt mij niet de juiste weg. Het vertroebelt je relaties een beetje (je FK wijst naar een arbitraire kolom die je apart moet optimaliseren).
Offline Frank56 - 14/11/2014 13:12 (laatste wijziging 14/11/2014 13:42)
Avatar van Frank56 Nieuw lid Ik heb de kolommen die alleen de antwoorden 1 of 0 bevatten INT gemaakt.

De kolom leer van de tabel leerlinglijst heb ik op PRIMARY KEY gezet, de andere PRIMARY KEY met AUTO_INCREAMENT heb ik daarvoor moeten weghalen.

In de tabellen met antwoorden, zoals t0401arg heb ik ook de PRIMARY KEY'S weggehaald en van de kolommen leerlingnummer2 in deze antwoordtabellen heb ik PRIMARY KEY'S gemaakt. Vervolgens heb ik de FOREIGN KEY'S in deze antwoordmodellen hierop gezet met een relatie naar leerlinglijst.leer.

Het gevolg is dat een leerling niet twee keer zijn antwoorden kan inleveren en ik zonder AUTO_INCREAMENT geen informatie meer uit de database kan verwijderen. Dat laatste kan ik waarschijnlijk voorkomen door niet de PRIMARY KEY op leerlingnummer2 te zetten, maar de UNIQUE KEY. Kan dat zonder problemen?

Citaat:
Aha, en de tekst is ook de antwoord op een vraag (en zoja, hoe beoordeel je of deze goed is?), of iets anders? En telt deze nog op een of andere manier mee in de berekening van het "eindcijfer"? Elk record van zo'n tabel vormen dus de toetsresultaten van zo'n leerling? Wegen alle vragen even zwaar (altijd maximale score 1), of kunnen deze ook een ander gewicht hebben?

Een mogelijk andere aanpak is bijvoorbeeld: je zou een tabel "toetsen" aan kunnen maken (met alle (meta)data omtrent een toets), een tabel "toets_vragen" (met hierin alle informatie omtrent een toetsvraag (bijvoorbeeld type: text of score en het "gewicht" van een vraag)) en een tabel "toets_antwoorden" (met hierin de antwoorden die een specifieke leerling bij een specifieke toets heeft gegeven). Er zijn eindeloos veel varianten mogelijk. Het uitrekenen van een gemiddelde wordt dan volgens mij wat eenvoudiger (je kunt dan gebruik maken van SUM en COUNT). Daarnaast helpt het wellicht ook dat deze "antwoorden" tabel enkel uit numerieke kolommen bestaat, volgens mij kon er dan een extra optimalisatie plaatsvinden maar ik heb hier geen bewijs voor / voorbeeld van, dit staat mij bij uit een vaag ver verleden.


De tekst is geen antwoord op een vraag, maar de naam van een leraar en de eigen naam ter controle. Deze namen moeten in elke antwoordentabel voorkomen en ik kan er geen aparte kolom van maken, omdat alle gegevens ad random binnen komen. Klopt dit?

De vragen wegen niet allemaal even zwaar, maar de score is altijd 1 of 0. Ik kan de verschillende weging niet opvangen met het geven van meer punten. Het cijfer van het ene onderdeel wordt berekend met cijfer= 9*score gedeeld door schaallengte + 1 en de andere met cijfer= 18*score gedeeld door schaallengte -8 (zie bijlage).

Ik zou de antwoordentabel dus moeten splitsen in vragen met verschillende zwaarte. Het gevolg is dat de leerlingen voor elke toetsonderdeel op een aparte link moeten klikken. Of kan ik de gegevens in dezelfde PHP-code naar twee tabellen verwijzen?

Ik dacht dat je COUNT en AVG alleen kon gebruiken in aparte kolommen. Kan dat ook op RECORDS?

Plaatscode: 142408

Plaatscode: 142409

Plaatscode: 142410

Plaatscode: 142411

mod edit: lappen code...
Offline Thomas - 14/11/2014 14:47
Avatar van Thomas Moderator
Citaat:
De tekst is geen antwoord op een vraag, maar de naam van een leraar en de eigen naam ter controle. Deze namen moeten in elke antwoordentabel voorkomen en ik kan er geen aparte kolom van maken, omdat alle gegevens ad random binnen komen. Klopt dit?
??? Kun je de leraren-informatie niet in een aparte tabel opslaan en hier aan refereren? Je zou zelfs je login-functionaliteit zo aan kunnen passen zodat leraren alleen hun eigen toetsen kunnen invoeren/aanpassen? Een naam lijkt mij ook foutgevoelig... Dus zelfs al heb je een stagiair(e) die alles invoert (van meerdere docenten) zou het beter zijn om de naam uit een dropdownmenu te kiezen? Daarnaast, je voert antwoorden in per toets correct? Zou het niet veel eenvoudiger zijn om eerst een(malig) een toets aan te maken, dan de vragen te definieren en dan de antwoorden in te gaan voeren? Kan het voorkomen dat meerdere docenten een toets nakijken? Al dit soort vragen bepalen de structuur van je database!

Citaat:
Het gevolg is dat een leerling niet twee keer zijn antwoorden kan inleveren en ik zonder AUTO_INCREAMENT geen informatie meer uit de database kan verwijderen. Dat laatste kan ik waarschijnlijk voorkomen door niet de PRIMARY KEY op leerlingnummer2 te zetten, maar de UNIQUE KEY. Kan dat zonder problemen?
Dit is alleen een vraag die jij kunt beantwoorden want dit hangt af van het gedrag van je data. Als een van de bovenstaande zaken een probleem vormt, dan moet je daar in je ontwerp rekening mee houden.

Citaat:
De vragen wegen niet allemaal even zwaar, maar de score is altijd 1 of 0. Ik kan de verschillende weging niet opvangen met het geven van meer punten. Het cijfer van het ene onderdeel wordt berekend met cijfer= 9*score gedeeld door schaallengte + 1 en de andere met cijfer= 18*score gedeeld door schaallengte -8 (zie bijlage).
Dit klinkt als een eigenschap van een toets, "rekensleutel" o.i.d.. Deze informatie kun je ergens opslaan, en op grond daarvan (in MySQL of in PHP) je berekening hier op aan laten sluiten...

Citaat:
Ik zou de antwoordentabel dus moeten splitsen in vragen met verschillende zwaarte. Het gevolg is dat de leerlingen voor elke toetsonderdeel op een aparte link moeten klikken. Of kan ik de gegevens in dezelfde PHP-code naar twee tabellen verwijzen?
Of je maakt onderscheid in een aparte kolom, zoals ik al eerder voorstelde.

Citaat:
Ik dacht dat je COUNT en AVG alleen kon gebruiken in aparte kolommen. Kan dat ook op RECORDS?
Nee, maar een antwoord-per-kolom-in-een-aparte-tabel is ook een beetje de richting die ik je op probeerde te sturen. Ik denk dat de herbezinning nog niet echt compleet is, ik bedoel, het enige wat je hebt veranderd zijn de kolomtypes, verder is de structuur nagenoeg hetzelfde. Mogelijk gaan berekeningen nu (wat) sneller maar ik denk dat je beter gediend bent met een (compleet) herontwerp.

Dit moet denk ik gepaard gaan met een omslag in je denkwijze. Nu is het zo dat je per toets een tabel maakt, en per vraag + antwoord een kolom in die tabel. Wat ik probeer te communiceren (en denk dat beter is) is een toets-tabel, een vraag-tabel en een antwoord tabel. Maar voordat je bij dat punt aanbeland moet je nadenken over hoe je dit aanpakt. Als je eenmaal een plan hebt, is het opstellen van je database min of meer het uitschrijven van je plan...

Om te komen tot dit plan moet je weten hoe je data eruitziet, en hoe deze zich gedraagt. Ik heb het idee dat ik (te)veel moeite moet doen om deze informatie te verkrijgen. Zoals ik al eerder voorstelde: omschrijf eens in lopende volzinnen wat je applicatie zou moeten doen, wat zijn de verschillende spelers in dit systeem etc..

Ik kan je niet overtuigen van het voordeel van een alternatieve aanpak, maar ik zou je wel een voorbeeld kunnen geven: stel dat je de vragen van een toets in een aparte tabel opslaat. Vervolgens zou je deze informatie kunnen gebruiken voor:
- het genereren van een formulier voor de invoer van antwoorden
dit it veel foutONgevoeliger dan het uitschrijven van een hard-coded formulier, en je hoeft de code voor het genereren van het formulier voor wat voor toets dan ook maar EEN KEER op te stellen, dit bespaart je ontzettend veel werk

Is er een reden waarom je je structuur niet wilt aanpassen? Ik neem aan dat je al gestopt was met het invoeren van gegevens op het moment dat bleek dat je webserver onderuit ging?

Anyway. Ik heb een beetje het idee dat er geen voortgang meer is in dit alles, dus vanaf nu ga ik wat terughoudender zijn in het geven van reacties, dit kost mij teveel tijd.
Offline Frank56 - 14/11/2014 18:20
Avatar van Frank56 Nieuw lid Voortgang is er zeker.

Nu is de data niet meer corrupt, en ik ben erg blij met jouw uitleg om dit te kunnen realiseren.

Maar een antwoord-per-kolom-in-een-aparte-tabel begrijp ik niet.

Ik zie het zo voor me dat elke leerling een aparte tabel krijgt met alle antwoorden in 1 kolom.
Dat betekent dat ik van tevoren 200 aparte tabellen moet maken, en daar heb ik geen tijd voor. Of dat er automatisch per leerling aparte tabellen gegenereerd worden en ik weet niet hoe ik dat moet doen. Of dat er een tabel is met het leerlingnummer in de bovenste cel en daaronder alle antwoorden.

Als je me een site geeft waar dat wordt uitgelegd, houd ik me aanbevolen. Ik heb hem niet kunnen vinden.



Offline Thomas - 14/11/2014 23:17 (laatste wijziging 14/11/2014 23:24)
Avatar van Thomas Moderator
Citaat:
Dat betekent dat ik van tevoren 200 aparte tabellen moet maken, en daar heb ik geen tijd voor.
Dat stel ik ook niet voor, wat ik voorstel staat al in mijn vorige antwoord:
Citaat:
Wat ik probeer te communiceren (en denk dat beter is) is een toets-tabel, een vraag-tabel en een antwoord tabel.
Zoals ik het zie, heb je nu al meerdere tabellen die hetzelfde doen: t0401form, t0401spel, t0401woord en weet ik veel welke tabellen je allemaal nog meer hebt. En in die opzet heb je inderdaad ook elke keer een nieuwe tabel nodig voor een toets (of wat het ook moge zijn). Mijn voorstel gaat voor een generieke aanpak waarbij je maar 3 tabellen nodig hebt voor de opslag van toets-data (toetsen, vragen, resultaten). Daarnaast heeft deze opzet mogelijk nog andere voordelen, bijvoorbeeld dat je deze kunt gebruiken om je formulier-pagina's automatisch te genereren, in plaats van deze elke keer helemaal uit te schrijven. Dit alles staat al in mijn vorige antwoord.

Ik draag mogelijke oplossingen aan, maar je herkent deze niet als zodanig of begrijpt deze niet. Er is geen "site" waar kant-en-klare oplossingen staan specifiek voor jouw automatiseringsvraagstuk. Je zult dit zelf uit moeten denken, want pogingen om uitgelegd te krijgen hoe je data precies functioneert zijn min of meer gestrand (ik heb hier echt meerdere keren om gevraagd). In plaats daarvan probeer ik je dan maar wat pointers te geven over hoe je je database kunt vormgeven... Ik denk echter dat het kennishiaat op dit moment nog te groot is om over te kunnen brengen wat ik bedoel. Het komt simpelweg niet aan.

Door shortcuts te nemen / geen slimmigheden in te bouwen in je database zul je later veel meer werk moeten verzetten. Daarnaast wordt de hele zaak een trage en foutgevoelige warboel. Maar als je graag eindeloos aan de molen wilt draaien bij het schrijven van de rest van je code voor je formulieren en weet ik wat meer, dan wens ik je veel succes. Denk eerst zaken uit voordat je ze gaat bouwen. En ga je database pas vullen als je klaar bent met bouwen. Maar misschien is het goed dat je hier zelf tegenaan loopt, een gebrande hand is de beste leermeester.

Dingen hebben een zekere volgorde. Als je in het midden van een boek begint is de kans vrij groot dat je geen touw kunt vastknopen aan het verhaal.

EDIT: Ik begrijp nu ook je oorspronkelijke vraag (beter). De vraag is echter, WAAROM zou je incomplete informatie willen bekijken? ... En als je dit al wilt, splits dit dan in verschillende queries op, in plaats van daar een query van te maken... Of verplaats het rekenwerk naar PHP...
Offline Frank56 - 15/11/2014 11:38
Avatar van Frank56 Nieuw lid Nu meen ik te begrijpen waarom je meer informatie van mij wilde hebben. 

Waarschijnlijk bedoel je met antwoord-model de antwoorden van de toets.

Door zowel de verschillende toetsen, de vragen en de antwoorden in een aparte tabel op te nemen, kun je snel een toets genereren. Dat is eigenlijk best wel een goed idee.

Ik heb antwoord-tabel steeds opgevat als antwoord-tabel van leerlingen waarin de behaalde punten komen te staan. En daar kan ik geen PRIMARY KEY op zetten, want de antwoorden op verschillende toetsonderdelen die in evenveel verschillende tabellen binnenkomen en waarvan het puntenaantal per leerling daarna in queries opgeteld en berekend wordt, worden ad-random gegeven. De enige unieke sleutel is leerlingnummer2 die verbonden is met een tabel waarin meer dan 1000 leerlingnummers staan. Hopelijk begrijp je dat ik zo'n ingevulde tabel met zoveel records niet op internet kan zetten.

Hoe ik de antwoorden uit het antwoord-model moet vergelijken met de antwoorden die de leerlingen gegeven hebben, weet ik nog niet. Hier ga ik over nadenken. Volgens mij kom ik er niet onderuit om naast de toets-tabel, de vraag-tabel en het antwoord-model ook nog een extra tabel te maken voor de behaalde punten van de leerlingen met leerlingnummer2 als unieke sleutel.

Je hebt gelijk met wat je in EDIT stelt. Ik moet de behaalde cijfers op dit moment niet tijdens de toets door 200 leerlingen laten opvragen. Dat kost te veel geheugen. Maar ... ik wil dat uiteindelijk wel, dus ik ga erover nadenken hoe ik dat in de toekomst wel mogelijk kan maken. Het verplaatsen van het rekenwerk naar PHP is hierbij een 'must'. Dank je wel voor deze aanwijzing.
Offline Thomas - 16/11/2014 13:25 (laatste wijziging 18/11/2014 15:49)
Avatar van Thomas Moderator EDIT: lol, die afbeelding klopte niet - is inmiddels vervangen (zie hieronder)

Citaat:
Door zowel de verschillende toetsen, de vragen en de antwoorden in een aparte tabel op te nemen, kun je snel een toets genereren. Dat is eigenlijk best wel een goed idee.
Voor het genereren van een invulformulier voor de antwoorden op toetsvragen heb je de id's nodig van de toetsvragen, die gebruik je om de antwoorden aan de juiste vraag te koppelen. En je gebruikt het leerling-id om de antwoorden te koppelen aan een leerling. Ik zal je verderop een voorbeeld geven, want ik krijg niet echt de indruk dat je begrijpt hoe je dit soort verbanden aan kunt leggen dmv primary / foreign keys.

Citaat:
Ik heb antwoord-tabel steeds opgevat als antwoord-tabel van leerlingen waarin de behaalde punten komen te staan. En daar kan ik geen PRIMARY KEY op zetten, want de antwoorden op verschillende toetsonderdelen die in evenveel verschillende tabellen binnenkomen en waarvan het puntenaantal per leerling daarna in queries opgeteld en berekend wordt, worden ad-random gegeven. De enige unieke sleutel is leerlingnummer2 die verbonden is met een tabel waarin meer dan 1000 leerlingnummers staan. Hopelijk begrijp je dat ik zo'n ingevulde tabel met zoveel records niet op internet kan zetten.
1000 records is niets. Maar als je tabelstructuur niet goed in elkaar zit zijn 100 records al teveel...

Ter vergelijking: een databasedump van sitemasters is circa 150 megabyte aan text. Dit forum heeft bijna 40,000 berichten met bijna 225,000 reacties. Nu zal ik de eerste zijn die zal toegeven dat de code en databasequeries (zwaar) verouderd zijn, maar omdat er toch wel wat verstandige beslissingen zijn genomen (vornamelijk ten aanzien van databasestructuur) is het forum niet onacceptabel langzaam. Ook draait deze site bij mijn weten niet op een megazware webserver. Op dit moment ben ik wat code aan het bijwerken die er effectief voor zorgt dat het aantal queries dat per page access wordt uitgevoerd nagenoeg wordt gehalveerd. Op dit moment loopt alles nog redelijk soepel, en ik hoop dat het na afloop allemaal iets sneller gaat. Maar hier merk je verder niet zoveel van als bezoeker. Als communicatie met je database er voor zorgt dat de boel helemaal vastloopt is er ergens iets grondig mis.

Het doel van een antwoord-tabel is het koppelen van een vraag aan een leerling, hierbij geeft een score kolom aan wat de beoordeling van de vraag is. Een primary key is bedoeld om een tabelrecord te identificeren. Een enkele id uit een andere tabel lijkt mij nooit een geschikte kandidaat om in een tweede tabel als primary key te dienen... Primary en foreign keys zijn geen syntactische suiker, zodat je met je toverstaf zwaait en alles is ineens efficient, nee. Deze kolommen definieren de verbanden tussen tabellen en zeggen dus iets over het gedrag van je data.

Citaat:
Hoe ik de antwoorden uit het antwoord-model moet vergelijken met de antwoorden die de leerlingen gegeven hebben, weet ik nog niet. Hier ga ik over nadenken. Volgens mij kom ik er niet onderuit om naast de toets-tabel, de vraag-tabel en het antwoord-model ook nog een extra tabel te maken voor de behaalde punten van de leerlingen met leerlingnummer2 als unieke sleutel.
Nee, de antwoorden-tabel is de tabel waar dit allemaal samenkomt. Het feit dat je dit niet inziet geeft voor mij min of meer aan dat je het niet begrijpt.

Citaat:
Je hebt gelijk met wat je in EDIT stelt. Ik moet de behaalde cijfers op dit moment niet tijdens de toets door 200 leerlingen laten opvragen. Dat kost te veel geheugen.
Nee, dit is simpelweg onzinnig.

Weet je wat. Tegen beter weten in geef ik je een voorbeeld. Hopelijk begrijp je dan beter hoe primary/foreign keys werken en hoe je ze gebruikt. Als je (blind) besluit om onderstaande opzet te gebruiken dan mag dit, maar ik ga je hier verder niet mee helpen. Dit is slechts een oplossing, niet de oplossing. Ik weet ook niet of het de oplossing is voor wat jij probeert te bereiken (want dit is mij nog steeds niet duidelijk). Ben je hierbij ook bewust van het feit dat er aannames zijn gedaan waarmee ontwerpbeslissingen zijn genomen.

Bekijk de volgende afbeelding. Dit is een redelijk abstracte representatie van wat ik voor ogen had. Hieronder staat een toelichting van deze afbeelding.

tabel toetsen
id - het id waarmee dit record wordt geidentificeerd, dit is de PK van deze tabel
omschrijving - waar de toets over gaat
data - wat je hier verder nog in kwijt wilt, datum van afleggen of wat dan ook
score_berekening - en bijvoorbeeld deze kolom: beschrijft hoe het eindcijfer berekend moet worden (volgens mij waren hier (tot nu toe?) twee recepten voor)

Het id van deze tabel is enkel bedoeld om een uniek nummer toe te wijzen aan een toets en heeft verder geen "betekenis".

tabel toets_vragen
id - het id waarmee dit record wordt geidentificeerd, dit is de PK van deze tabel
toets_id - de toets waartoe deze vraag behoort, dit is een FOREIGN KEY
omschrijving - deze kolom kan beschrijven waar de vraag over ging, of een referentie naar een externe unieke code bevatten of wat dan ook
volgorde - misschien is deze kolom ook verstandig, je kunt dan de volgorde van de vragen een vast verloop geven (en rangschikken in je queries met ORDER BY)

tabel leerlingen
id - het id waarmee dit record wordt geidentificeerd, dit is de PK van deze tabel
leerlingnummer - dit is het externe unieke nummer van een leerling, in deze tabel zou je een UNIQUE constraint kunnen opleggen aan deze kolom, om ervoor te zorgen dat deze nummers ook uniek zijn binnen deze database-tabel

Ik denk dat er een aantal voordelen zijn om binnen je database niet te refereren aan leerlingen via het externe leerlingnummer. Een daarvan is "ontkoppeling van de buitenwereld". Het enige verbindende element met de buitenwereld is de "leerlingnummer" kolom. Voor de rest gebruik je de interne nummering.

Okay, een gedachten experiment. Stel je kiest voor jouw aanpak, waarbij je alles aan elkaar knoopt via het leerlingnummer. Dan wordt besloten om de leerlingnummers om te nummeren. Oei. Je zult dan een heleboel tabellen moeten bijwerken. Daarnaast zit je met je foreign keys. Die zorgen ervoor dat je dit soort kolommen niet zomaar kunt aanpassen want deze voorziening is JUIST BEDOELD om je informatie kloppend te houden. Je zou dan dus een conversiescript moeten schrijven die al deze kolommen omnummert waarbij je je primary/foreign keys tijdelijk uitschakelt... *BRRR*
En wat als het leerlingnummer zo verandert dat hier ook letters of andere symbolen in komen? Dan zou je zelfs de STRUCTUUR van je database op meerdere plaatsen moeten wijzigen. Zou het niet veel beter zijn als leerlingnummer één kolom in je database was zonder betekenis?

Oh en het eerdergenoemde "bezwaar" wat je eerder noemde (geloof ik?) dat je al deze leerlingen dan in zou moeten voeren: als je het nog niet lukt om hiervoor een importscript te schrijven, dan zou ik je afraden om met grotere/ingrijpendere dingen bezig te zijn...

tabel toets_antwoorden
id - het id waarmee dit record wordt geidentificeerd, dit is de PK van deze tabel
vraag_id - de vraag waartoe dit antwoord behoort, dit is een FOREIGN KEY
leerling_id - de leerling die deze vraag beantwoord heeft, ook dit is een FOREIGN KEY
score - de normering die de leerling heeft gekregen voor het beantwoorden van een vraag

Met enige fantasie kun je je misschien ook een voorstelling maken van de queries die je nu kunt schrijven om de data ook weer uit de database te trekken. Ik denk dat die een stuk beter leesbaar zijn dan wat ik tot nu toe heb gezien. Een heldere database-opzet kan ENORM helpen bij de leesbaarheid (en daarmee het BEGRIP) van queries.
Offline Frank56 - 29/11/2014 22:44
Avatar van Frank56 Nieuw lid Dank je wel.

Dit werkt goed.

Kun je me uitleggen waarom je beter elk antwoord van een leerling in een apart record kunt zetten? Heeft dit alleen te maken met het feit dat je nu COUNT kunt gebruiken of heeft het nog andere voordelen, bijvoorbeeld wat snelheid of betrouwbaarheid betreft?

Verder loop ik tegen het probleem aan dat <input type="submit" value="registreren"> ook werkt als een leerling op enter drukt of de pijltjestoets gebruikt. Kun je in code vastleggen dat de antwoorden alleen geregistreerd worden als je op de button klikt?






Offline Thomas - 30/11/2014 16:22
Avatar van Thomas Moderator
Citaat:
Kun je me uitleggen waarom je beter elk antwoord van een leerling in een apart record kunt zetten? Heeft dit alleen te maken met het feit dat je nu COUNT kunt gebruiken of heeft het nog andere voordelen, bijvoorbeeld wat snelheid of betrouwbaarheid betreft?
Er is geen beter of slechter, het enige wat je zou moeten doen is het nemen van (ontwerp)beslissingen op basis van argumenten en het "gedrag" van je data.

Argumenten voor deze structuur zouden zijn:
flexibiliteit
Het stelt je in staat om de samenstelling van een toets (als het een toets is) aan te passen zonder de structuur van je database aan te passen, en ook om toetsen toe te voegen zonder het creëren van een compleet nieuwe tabel (wat in feite ook een structuuraanpassing is). Structuuraanpassingen zijn slecht (niet?) te binden aan de regels die van toepassing zijn op de data in je tabellen. Als je dus een systeem zou hebben die tabellen creëert en inhoudelijk aanpast dan wordt het lastiger (zo niet haast onmogelijk) om te waarborgen dat je data kloppend blijft, je hebt in ieder geval geen middel meer om dit af te dwingen. Door middel van een dynamische opzet kun je je "structuur" vrij aanpassen, maar blijf je binnen de spelregels (key constraints) die je aan je tabellen(data) hebt opgelegd.

leesbaarheid
In jouw (inmiddels oude?) opzet had je queries zoals deze:
  1. SELECT *,
  2. ROUND((((regelk1+regelk2+regelk3+regelk4)*18)/4)-8,1) AS nehar,
  3. ROUND((((wwspel1+wwspel2+wwspel3+wwspel4+overigew1+overigew2+overigew3+overigew4+interp1+interp2+interp3+interp4+taalkundigontl1+taalkundigontl2+taalkundigontl3+taalkundigontl4+redekundigontl1+redekundigontl2+redekundigontl3+redekundigontl4)*18)/20)-8,1) AS nehat1,
  4. ROUND((((life1+life2+life3+life4+life5+life6+life7+life8+food1+food2+food3+food4+food5+food6+food7+food8+food9+food10+key1+key2+key3+key4+key5+key6+key7+key8)*18)/26)-8,1) AS enhat1,
  5. ROUND((((jean1+jean2+jean3+jean4+jean5+jean6+jean7+jean8+jean9)*18)/9)-8,1) AS fahat1,
  6. ROUND((((ww1+ww2+ww3+ww4+ww5+ww6+ww7+naamv1+naamv2+naamv3+naamv4+naamv5+naamv6+woordb1+woordb2+woordb3+woordb4+woordb5+woordb6+video1+video2+tekst1+tekst2+tekst3+tekst4)*18)/25)-8,1) AS duhat1,
  7. ROUND((((formul1+formul2+formul3+formul4)*9)/4)+1,1) AS nehat2,
  8. ROUND((((concerns1+concerns2+concerns3+concerns4+concerns5+concerns6+concerns7+concerns8+concerns9+concerns10+concerns11+concerns12+exam1+exam2+exam3+exam4+exam5+exam6+exam7+exam8+exam9+exam10+exam11+exam12+folk1+folk2+folk3+folk4+folk5+folk6+folk7+folk8+folk9+folk10+folk11+folk12+folk13+folk14+folk15)*9)/39)+1,1) AS enhat2,
  9. ROUND((((prets1+prets2+prets3+prets4+prets5+prets6+courir1)*9)/7)+1,1) AS fahat2,
  10. ROUND((((past1+past2+past3+past4+woordb7+woordb8)*9)/6)+1,1) AS duhat2,
  11. ROUND((((tekstbegrip1+tekstbegrip2+tekstbegrip3)*9)/3)+1,1) AS nehai,
  12. ROUND((((((regelk1+regelk2+regelk3+regelk4)*18)/4)-8)+((((wwspel1+wwspel2+wwspel3+wwspel4+overigew1+overigew2+overigew3+overigew4+interp1+interp2+interp3+interp4+taalkundigontl1+taalkundigontl2+taalkundigontl3+taalkundigontl4+redekundigontl1+redekundigontl2+redekundigontl3+redekundigontl4)*18)/20)-8)+(((formul1+formul2+formul3+formul4)*9/4)+1)+((((tekstbegrip1+tekstbegrip2+tekstbegrip3)*9)/3)+1))/4,1) AS cijferne,
  13. ROUND((((((life1+life2+life3+life4+life5+life6+life7+life8+food1+food2+food3+food4+food5+food6+food7+food8+food9+food10+key1+key2+key3+key4+key5+key6+key7+key8)*18)/26)-8)+((((concerns1+concerns2+concerns3+concerns4+concerns5+concerns6+concerns7+concerns8+concerns9+concerns10+concerns11+concerns12+exam1+exam2+exam3+exam4+exam5+exam6+exam7+exam8+exam9+exam10+exam11+exam12+folk1+folk2+folk3+folk4+folk5+folk6+folk7+folk8+folk9+folk10+folk11+folk12+folk13+folk14+folk15)*9)/39)+1))/2,1) AS cijferen,
  14. ROUND((((((jean1+jean2+jean3+jean4+jean5+jean6+jean7+jean8+jean9)*18)/9)-8)+((((prets1+prets2+prets3+prets4+prets5+prets6+courir1)*9)/7)+1))/2,1) AS cijferfa,
  15. ROUND((((((ww1+ww2+ww3+ww4+ww5+ww6+ww7+naamv1+naamv2+naamv3+naamv4+naamv5+naamv6+woordb1+woordb2+woordb3+woordb4+woordb5+woordb6+video1+video2+tekst1+tekst2+tekst3+tekst4)*18)/25)-8)+((((past1+past2+past3+past4+woordb7+woordb8)*9)/6)+1))/2,1) AS cijferdu,
  16. regelk1+regelk2+regelk3+regelk4+wwspel1+wwspel2+wwspel3+wwspel4+overigew1+overigew2+overigew3+overigew4+interp1+interp2+interp3+interp4+taalkundigontl1+taalkundigontl2+taalkundigontl3+taalkundigontl4+redekundigontl1+redekundigontl2+redekundigontl3+redekundigontl4+formul1+formul2+formul3+formul4+tekstbegrip1+tekstbegrip2+tekstbegrip3 AS totaal
  17. FROM hav
  18. INNER JOIN lijst
  19. ON hav.nr2=lijst.leer
  20. INNER JOIN nh
  21. ON nh.nr2=lijst.leer
  22. LEFT JOIN fh
  23. ON fh.nr2=lijst.leer
  24. LEFT JOIN dh
  25. ON dh.nr2=lijst.leer
  26. ORDER BY klas ASC

Misschien kunnen ingewijden hier wel chocola van maken, maar voor buitenstaanders is dit volstrekt onleesbaar. Daarnaast zijn dit soort queries nogal foutgevoelig (ga hier maar eens een ontbrekende letter of verkeerde cijfer in zoeken). Werk volgens het KISS-principe. Daarnaast, als je naar deze query kijkt doe je meerdere keren hetzelfde. Niet alleen in MySQL, maar ook in PHP en elders zou dit een alarmbel moeten doen rinkelen. Als je een bewerking herhaalt, dan kan zo'n stuk (SQL) code heel vaak vereenvoudigd worden. Ook is het zo dat je in jouw opzet voor elke nieuwe tabel een nieuwe query moet schrijven.

Als je een tabel structureel aanpast, dan houdt dat in jouw opzet ook een query aanpassing in. Als je een tabel toevoegt, dan houdt dat in jouw opzet ook een nieuwe query (en waarschijnlijk ook een (aantal) compleet nieuwe formulier-pagina('s) + nieuwe queries) in. Door een dynamische opzet wordt dit allemaal overbodig. Je hoeft maar één set van queries en pagina's te schrijven. Snap je hoe ontzettend veel werk dat scheelt, simpelweg door een andere (en m.i. eenvoudigere) aanpak te kiezen? En dit krijg je er dus allemaal gratis bij door de tijd te nemen om na te denken over je database-opzet. Dit resulteert in een stuk minder code / minder queries wat het geheel beter leesbaar en dus beter beheer(s)baar maakt.

Vergeet echter nooit wat je aan het doen bent (dit is een argument tegen): met deze dynamische opzet ben je min of meer een database binnen je database aan het definiëren. Nu is dat doorgaans niet per definitie een goed idee, maar ik denk dat het in dit geval geoorloofd is gezien je hiermee een enorme (potentiële) tijdswinst opdoet. Het moet natuurlijk nog steeds aansluiten bij het gedrag van je data, anders moet je misschien een andere oplossing kiezen. Ook moet je de schaalbaarheid van je oplossing in de gaten houden, maar de aantallen die ik je heb horen noemen zijn nou niet bepaald wereldschokkend.

Overigens: het is niet de bedoeling dat je mijn oplossing volgt omdat ik denk dat die beter is, je moet deze volgen als je er zelf van overtuigd bent dat deze gaat werken. JIJ weet namelijk wat je (uiteindelijk) wilt kunnen doen en hoe je data precies in elkaar steekt, ik heb slechts flarden van dit alles (met veel pijn en moeite, mag ik wel zeggen) kunnen ontfutselen.

Ik zou dus ook een deel van het rekenwerk naar PHP verplaatsen, zoals ik in mijn vorige bericht heb voorgesteld.

Citaat:
Verder loop ik tegen het probleem aan dat <input type="submit" value="registreren"> ook werkt als een leerling op enter drukt of de pijltjestoets gebruikt. Kun je in code vastleggen dat de antwoorden alleen geregistreerd worden als je op de button klikt?

Euh, leerlingen? Tot nu toe dacht ik dat hetgeen je aan het maken was een soort van administratief systeem was voor het vastleggen van toetsantwoorden, maar je gebruikt dit systeem dus (ook?) voor het afleggen van een toets door een leerling zelf?

Afhankelijk van de gebruiker en het doel van een pagina zullen deze op verschillende manieren opgezet moeten worden omdat de insteek compleet anders is... Wat je in jouw geval waarschijnlijk wilt is het afvangen van bepaalde toetsaanslagen. Dit doe je met JavaScript. Wat ook helpt is het controleren van je formulierinvoer voor/bij verwerking om te bepalen of de gegevens volledig en kloppend zijn voordat deze verwerkt worden... Dit laatste kun je ook via PHP doen maar de makkelijkste oplossing is JavaScript.

Heb je hier al op gezocht? Op het forum, in de scripts, met Google?

Daarnaast: deze thread ging/gaat over SQL en de database-opzet, niet over formulierverwerking. In het kader van separation of concerns lijkt het mij niet verstandig om hier binnen deze thread een discussie over te starten. Hier valt genoeg over te vinden als je zoekt.

Ik hoop overigens ook dat je jouw applicatie nog niet in gebruik hebt genomen terwijl je nog bezig bent met de ontwikkeling ervan. Dat is een recipe for disaster.
Offline Frank56 - 01/12/2014 15:57
Avatar van Frank56 Nieuw lid Dank je wel voor de tip over formulierinvoer. Dat is nu gelukt.

Citaat:
Ik hoop overigens ook dat je jouw applicatie nog niet in gebruik hebt genomen terwijl je nog bezig bent met de ontwikkeling ervan. Dat is een recipe for disaster.


Nee, dat heb ik nog niet gedaan. Gelukkig maar ... De opzet werkt alleen met 1 antwoord van 1 leerling. De kolom leerling_id in tabel toets_antwoorden staat op uniek, omdat ik anders niet met een FOREIGN KEY kan werken. Dit impliceert dat elke leerling maar 1 vraag kan maken, en dat is niet de bedoeling.
Gesponsorde links
Je moet ingelogd zijn om een reactie te kunnen posten.
Actieve forumberichten
© 2002-2024 Sitemasters.be - Regels - Laadtijd: 1.083s