login  Naam:   Wachtwoord: 
Registreer je!
 Forum

Mysql output in checkbox (Opgelost)

Offline sanderrebry - 24/10/2013 13:07 (laatste wijziging 24/10/2013 13:08)
Avatar van sanderrebryLid Ik heb twee tabellen, printtoplate_ophangsystemen en printtoplate_artikelen
Graag had ik de volledige output van printtoplate_ophangsystemen in checkboxen en waar de id gekoppeld is aan printtoplate_artikelen in checkboxen checked..

printtoplate_ophangsystemen
ID | NAAM
1 Velcro
2 H-profiel

printtoplate_artikelen
ID | ARTIKEL | ophangsysteem_id
1 Dibond 1,2

Voorlopig heb ik dit scriptje


  1. $query_ophangsystemen = "SELECT printtoplate_ophangsystemen.naam AS ophang,printtoplate_ophangsystemen.id AS id FROM printtoplate_ophangsystemen INNER JOIN printtoplate_artikelen ON FIND_IN_SET(printtoplate_ophangsystemen.id,printtoplate_artikelen.ophangsysteem_id) > 0 WHERE printtoplate_artikelen.id='".$id."'";
  2. // query vaste ophangsystemen
  3. $result_ophang = mysql_query($query_ophangsystemen) or die(mysql_error());
  4.  
  5. while($row_ophang = $query_ophangsystemen = mysql_fetch_array($result_ophang)) // Alle vaste ophangsystemen uit database halen
  6. {
  7. echo '<tr><td><input type="checkbox" checked name="ophangsysteem[]" value="'.$row_ophang['id'].'"></td><td>'.$row_ophang['ophang'].'</td></tr>';
  8. }

Iemand een idee?
Bedankt!

14 antwoorden

Gesponsorde links
Offline marten - 24/10/2013 13:36
Avatar van marten Beheerder Beste Sander,

Ten eerste zou ik een kleine aanpassing in je database structuur doen. Blijkbaar kan 1 artikel aan meerdere ophangsystemen behoren. Is het ook zo dat 1 ophangsysteem meerdere artikelen kan hebben? Dan is het namelijk een meer op meer relatie en heb je dus een koppeltabel nodig.

Een koppeltabel is niets meer dan een id, artikel_id en een ophangsysteem_id. Zo hoef je het dus niet komma gescheiden op te slaan. En kan je veel makkelijker een query maken voor de checkboxes.
Offline Thomas - 24/10/2013 14:06
Avatar van Thomas Moderator In beide gevallen (een artikel kan tot meerdere ophangsystemen behoren en/of een ophangsysteem bestaat uit/bevat meerdere artikelen) is, zoals marten al zei, een koppeltabel gerechtvaardigd zo niet noodzakelijk om e.e.a. gestructureerd op te slaan.

Af en toe kan kommagescheiden data handig zijn, maar in dit geval waarschijnlijk niet ;).
Offline sanderrebry - 24/10/2013 14:41
Avatar van sanderrebry Lid Beste,

Bedankt voor het snelle antwoord.
Het klopt inderdaad dat een artikel meerdere ophangsystemen kan hebben,gescheiden met een komma.
Kan je me even een voorbeeld geven hoe je dit precies zou doen?
Want ik gebruik namelijk een koppeltabel door INNER JOIN?
Bedankt!
Offline marten - 24/10/2013 14:47
Avatar van marten Beheerder Als je wilt dat de koppeling verplicht moet voorkomen gebruik je een INNER JOIN inderdaad.
Offline Thomas - 24/10/2013 15:28
Avatar van Thomas Moderator Aha, een ophangsysteem is een eigenschap van een artikel (klopt dit?). Het codefragment in je oorspronkelijke bericht lijkt onderdeel van een beheerpagina van een specifiek artikel, waarin je (onder andere?) kunt aangeven welke ophangsystemen dit artikel allemaal ondersteunt (klopt dit?).

Wat ik in dat geval zou doen, is een lijst van alle ophangsystemen afdrukken, en door middel van een LEFT JOIN op de koppeltabel bepalen of een artikel een zeker ophangsysteem heeft. Dit kun je in één query doen.

Ik zal hier later nog een voorbeeldje van fabriceren als edit op dit bericht (database structuur en bijbehorende code).
Offline sanderrebry - 24/10/2013 15:52
Avatar van sanderrebry Lid Beste FangorN,

De stelling van jouw klopt helemaal.
Als je hiervan een voorbeeldje hebt dan zou je mij super goed kunnen helpen ;)

Bedankt alvast voor de info!

Mvg,
Sander Rebry
Offline Thomas - 24/10/2013 16:56
Avatar van Thomas Moderator Weet niet of je MyISAM of InnoDB gebruikt, maar heb even snel iets in elkaar gezet in InnoDB (iets andere namen, maar de strekking lijkt mij wel duidelijk). Indien je MyISAM gebruikt zijn foreign keys niet mogelijk dacht ik.

Database structuur:
  1. CREATE TABLE ophangsystemen (
  2. id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  3. naam VARCHAR(255) NOT NULL
  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  5.  
  6.  
  7. CREATE TABLE artikelen (
  8. id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  9. naam VARCHAR(255) NOT NULL
  10. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  11.  
  12. CREATE TABLE artikel_ophangsystemen (
  13. artikel_id BIGINT(20) UNSIGNED NOT NULL,
  14. ophangsysteem_id BIGINT(20) UNSIGNED NOT NULL,
  15. PRIMARY KEY (artikel_id, ophangsysteem_id)
  16. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  17.  
  18. ALTER TABLE artikel_ophangsystemen ADD FOREIGN KEY (artikel_id) REFERENCES artikelen(id) ON DELETE CASCADE;
  19. ALTER TABLE artikel_ophangsystemen ADD FOREIGN KEY (ophangsysteem_id) REFERENCES ophangsystemen(id) ON DELETE CASCADE;


Test data:
  1. INSERT INTO artikelen (naam) VALUES ('Dibond'), ('test');
  2. INSERT INTO ophangsystemen (naam) VALUES ('Velcro'), ('H-profiel'), ('Drie']);
  3. INSERT INTO artikel_ophangsystemen (artikel_id, ophangsysteem_id) VALUES (1, 1), (1, 2), (2, 1), (2, 3);


Code:
  1. <?php
  2. function escape_output($in) {
  3. return htmlspecialchars($in, ENT_QUOTES);
  4. }
  5.  
  6. $geselecteerd_artikel_id = 1;
  7.  
  8. $query = 'SELECT o.id AS ohs_id, o.naam AS ohs_naam, ao.ophangsysteem_id
  9. FROM ophangsystemen o
  10. LEFT JOIN artikel_ophangsystemen ao ON (ao.ophangsysteem_id = o.id AND ao.artikel_id='.mysql_real_escape_string($geselecteerd_artikel_id).')';
  11. $res = mysql_query($query) or die(mysql_error());
  12. if (mysql_num_rows($res)) {
  13. ?><table><?php
  14. while ($row = mysql_fetch_assoc($res)) {
  15. // als ao.ophangsysteem_id de waarde NULL heeft, betekent dit dat dit ophangsysteem niet bij dit artikel voorkwam in de koppeltabel
  16. // in dat geval checken we de checkbox niet
  17. if ($row['ophangsysteem_id'] == NULL) {
  18. $checked = '';
  19. } else {
  20. $checked = ' checked="checked"';
  21. }
  22. ?><tr>
  23. <td>
  24. <input type="checkbox" name="ophangsystemen[]" id="ophangsysteem_<?php echo escape_output($row['ohs_id']) ?>" value="<?php echo escape_output($row['ohs_id']) ?>"<?php echo $checked ?> />
  25. <label for="ophangsysteem_<?php echo escape_output($row['ohs_id']) ?>"><?php echo escape_output($row['ohs_naam']) ?></label>
  26. </td>
  27. </tr><?php
  28. }
  29. ?></table><?php
  30. }
  31. ?>
Bedankt door: Wijnand, marten
Offline Wijnand - 25/10/2013 10:28
Avatar van Wijnand Moderator Dank je FangorN, die ON DELETE CASCADE is echt super handig, ik heb dat nog niet eerder gezien (wist wel dat het mogelijk was, maar nooit opgezocht). Weer wat geleerd!
Offline sanderrebry - 25/10/2013 15:39 (laatste wijziging 25/10/2013 15:40)
Avatar van sanderrebry Lid Heel erg bedankt, dit werkt inderdaad perfect.
Alleen krijg ik een error wanneer ik de FK toevoeg aan de tabel artikel_ophangsystemen.
Ik gebruik nochtans innoDB engine voor beide tabellen...
Iemand een idee?

Bedankt!
Offline Thomas - 25/10/2013 16:16
Avatar van Thomas Moderator @sanderrebry: dit hangt vaak samen met de reeds aanwezige waarden die in de tabel zitten waar je de foreign key op wilt aanbrengen. Bij het aanmaken van de foreign key wordt namelijk gecontroleerd of de data "klopt". Als je dus bijvoorbeeld op de artikel_ophangsystemen-tabel een foreign key probeert aan te maken waarin artikel 1, 2 en 3 voorkomt, maar in de artikelen-tabel (het tabel met de "originelen" zeg maar, waar gedefinieerd staat welke artikelen er allemaal zijn) waaraan je refereert komt alleen artikel 1 en 2 voor, dan zal MySQL hier over struikelen.

Een andere reden waarom het aanmaken van een foreign key kan mislukken is een verschil in typedefinitie tussen het foreign-key veld en het veld waar je de foreign key naar wilt laten verwijzen. Voorbeeld: zowel artikelen.id als artikel_ophangsystemen.artikel_id moeten van hetzelfde type zijn als je een foreign key op artikel_ophangsystemen.artikel_id wilt laten verwijzen naar artikelen.id.
Offline sanderrebry - 25/10/2013 17:10
Avatar van sanderrebry Lid Dit is gelukt, gegevens geexporteerd daarna de structuur aangepast en dan alle gegevens terug geimporteerd. Nu nog de juiste query zoeken voor die koppeling. Dus wanneer de checkbox unchecked mag die uit en wanneer checked is die gekoppeld...
Offline Thomas - 26/10/2013 00:11 (laatste wijziging 26/10/2013 00:19)
Avatar van Thomas Moderator Bedoel je de extra queries die uitgevoerd moeten worden om de koppeltabelgegevens aan te passen als je de informatie van een artikel (waaronder dus ophangsystemen) bijwerkt?

In mijn eerdere voorbeeld staat al hoe de ophangsystemen voor een bepaald artikel kunnen worden uitgelezen, hieronder staat in het kort beschreven hoe je deze bij kunt werken:

Gemakshalve heb ik maar even de hele code toegevoegd, je ziet zelf de nieuwe toevoegingen en ik ga er vanuit dat je dit zelf in je eigen code kunt opnemen.
Dit is een (voor mijzelf) werkend voorbeeld. Je zult dit zelf nog moeten aanpassen!

  1. <?php
  2. function escape_output($in) {
  3. return htmlspecialchars($in, ENT_QUOTES);
  4. }
  5.  
  6. // hier ga ik er gemakshalve van uit dat het artikel-id in de URL wordt doorgegeven via "artikel_id"
  7. // dit kan in jouw code anders zijn!
  8. $geselecteerd_artikel_id = isset($_GET['artikel_id']) && is_numeric($_GET['artikel_id']) ? $_GET['artikel_id'] : 1;
  9.  
  10. $submitting = $_SERVER['REQUEST_METHOD'] == 'POST';
  11.  
  12. if ($submitting) {
  13. // LET OP: Hier doe je zelf waarschijnlijk ook je EIGEN aanpassingen aan het artikel, die staan hier niet bij!
  14. // ...
  15.  
  16. // dit stuk gaat over het bijwerken van de koppeltabel
  17. mysql_query('START TRANSACTION'); // InnoDB specifiek
  18. // verwijderen
  19. mysql_query('DELETE FROM artikel_ophangsystemen WHERE artikel_id = '.$geselecteerd_artikel_id);
  20. // en alles weer toevoegen... als er iets toe te voegen is!
  21. if (isset($_POST['ophangsystemen'])) {
  22. foreach ($_POST['ophangsystemen'] as $ophangsysteem_id) {
  23. mysql_query('INSERT INTO artikel_ophangsystemen (
  24. artikel_id,
  25. ophangsysteem_id
  26. ) VALUES (
  27. '.mysql_real_escape_string($geselecteerd_artikel_id).',
  28. '.mysql_real_escape_string($ophangsysteem_id).'
  29. )') or die(mysql_error());
  30. }
  31. }
  32. mysql_query('COMMIT'); // InnoDB specifiek
  33.  
  34. // doorsturen naar artikelpagina, dit kan in jouw code natuurtlijk een andere actie zijn...
  35. header('Location: '.$_SERVER['PHP_SELF'].'?artikel_id='.$geselecteerd_artikel_id);
  36. } else {
  37. ?><form action="<?php echo escape_output($_SERVER['PHP_SELF']) ?>?artikel_id=<?php echo escape_output($geselecteerd_artikel_id) ?>" method="post"><?php
  38. $query = 'SELECT o.id AS ohs_id, o.naam AS ohs_naam, ao.ophangsysteem_id
  39. FROM ophangsystemen o
  40. LEFT JOIN artikel_ophangsystemen ao ON (ao.ophangsysteem_id = o.id AND ao.artikel_id='.mysql_real_escape_string($geselecteerd_artikel_id).')';
  41. $res = mysql_query($query) or die(mysql_error());
  42. if (mysql_num_rows($res)) {
  43. ?><table><?php
  44. while ($row = mysql_fetch_assoc($res)) {
  45. // als ao.ophangsysteem_id de waarde NULL heeft, betekent dit dat dit ophangsysteem niet bij dit artikel voorkwam in de koppeltabel
  46. // in dat geval checken we de checkbox niet
  47. if ($row['ophangsysteem_id'] == NULL) {
  48. $checked = '';
  49. } else {
  50. $checked = ' checked="checked"';
  51. }
  52. ?><tr>
  53. <td>
  54. <input type="checkbox" name="ophangsystemen[]" id="ophangsysteem_<?php echo escape_output($row['ohs_id']) ?>" value="<?php echo escape_output($row['ohs_id']) ?>"<?php echo $checked ?> />
  55. <label for="ophangsysteem_<?php echo escape_output($row['ohs_id']) ?>"><?php echo escape_output($row['ohs_naam']) ?></label>
  56. </td>
  57. </tr><?php
  58. }
  59. ?></table><?php
  60. }
  61. ?><button type="submit">submit</button>
  62. </form><?php
  63. }
  64. ?>



Wat je in feite doet is het verwijderen van de bestaande koppelsystemen voor het bewuste artikel, en daarna voeg je ze weer toe. Je hoeft dan namelijk niet te controleren of een record al aanwezig is of niet. Als je eenzelfde artikel-ophangsysteem-paar opnieuw probeert in te voegen gaat dit mis vanwege de PRIMARY KEY constraint: elke artikel-ophangsysteem-combinatie in de koppeltabel MOET uniek zijn. Daarom maak je het jezelf makkelijk door ze eerst weg te gooien, vervolgens voeg je ze opnieuw toe.

Nu wil je natuurlijk niet dat dit mis gaat (je verwijdert wel de koppelingen, maar bij het toevoegen gaat iets mis, dan ben je data kwijt). InnoDB heeft hier een voorziening voor: de transactie. Kortweg gezegd kun je een reeks van queries "als geheel" uitvoeren. Indien er iets misgaat wordt de hele transactie teruggedraaid, een transactie (reeks van queries) wordt dus altijd helemaal, of helemaal niet uitgevoerd. Dit helpt je verder met het kloppend houden van je data als er fouten in je code zitten. De kans dat ook je database-data hierdoor gecorrumpeerd raakt neemt hierdoor af. Maar je kunt het natuurlijk ook zonder transacties stellen, je hebt het niet per se nodig. Je start een transactie door middel van START TRANSACTION en als je met je reeks queries klaar bent COMMIT je alles. Als je niet van InnoDB gebruik maakt moet je deze twee regels weglaten.

Nog een opmerking: Bij het aanmaken van mijn foreign keys ben ik er van uitgegaan dat:
- een ophangsysteem verwijderd mag worden uit de database, ook als er nog artikelen bestaan die dit ophangsysteem gebruiken, de koppeltabel wordt dan opgeschoond (dit is in feite wat ON DELETE CASCADE inhoudt); het verwijderen van ophangsystemen wil je mogelijk niet toestaan zolang er artikelen zijn die dit ophangsysteem gebruiken; dit kun je afdwingen met de foreign key, maak de ophangsysteem-key in dat geval ON DELETE RESTRICT (of laat dit simpelweg achterwege want ON DELETE RESTRICT is default)

- een artikel verwijderd mag worden uit de database, ook al is deze gekoppeld aan een of meer ophangsystemen; dit is logisch, je wilt bij het verwijderen van een artikel ALLE informatie van een artikel weggooien, dus ook de koppelsysteem-gerelateerde informatie

Dit illustreert goed de kracht van InnoDB boven MyISAM: het kost je heel weinig moeite om de gegevens kloppend (referentieel integer) te houden en je kunt extra condities opleggen (o.a.) op het moment dat je gegevens probeert te verwijderen.

Hier geldt echter wel "with great power comes great responsibility". Als je InnoDB op volle toeren wilt gebruiken (foreign keys, transacties en de hele mikmak) moet je wel een gezond databaseontwerp hebben en enige kaas gegeten hebben van wat je aan het doen bent!
Bedankt door: Wijnand, sanderrebry
Offline sanderrebry - 26/10/2013 09:25
Avatar van sanderrebry Lid Beste FangorN,

Ik heb dit inmiddels toegepast.
Van harte bedankt voor de uitgebreide uitleg en vele tips!


Mvg,
Sander Rebry
Offline WouterJ - 26/10/2013 09:27
Avatar van WouterJ HTML gevorderde Zou je dan het juiste bericht als 'oplossing' willen markeren?
Gesponsorde links
Je moet ingelogd zijn om een reactie te kunnen posten.
Actieve forumberichten
© 2002-2024 Sitemasters.be - Regels - Laadtijd: 0.227s