Multiple Checkboxes sql query
Met mijn opleiding ben ik bezig met een webshop met daarin de volgende vraag:
Ik en mijn groepsgenoten willen bij de categorie pagina meerdere categorieën kunnen filteren en dit in de sql query kunnen plaatsen.
Heeft iemand een idee hoe dit moet?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST'){
$sql = "SELECT FROM shop WHERE title LIKE '%" . $_POST['q'] . "%'";
if(isset($_POST['cat'])){
$i=0;
foreach($_POST['cat'] AS $cat){
$sql .= ($i == 0) ? ' AND ' : ' OR ';
$sql .= 'cat = "' . $cat . '"';
$i++;
}
}
echo $sql;
/* Output: SELECT FROM shop WHERE title LIKE '%PHP%' AND cat = "boeken" OR cat = "cds" */
}
?>
<form method="POST">
<input type="search" name="q" /><br />
<label>Boeken</label>
<input type="checkbox" name="cat[]" value="boeken" />
<label>CD's</label>
<input type="checkbox" name="cat[]" value="cds" />
<label>Games</label>
<input type="checkbox" name="cat[]" value="games" />
<button>Zoeken</button>
</form>
if($_SERVER['REQUEST_METHOD'] == 'POST'){
$sql = "SELECT FROM shop WHERE title LIKE '%" . $_POST['q'] . "%'";
if(isset($_POST['cat'])){
$i=0;
foreach($_POST['cat'] AS $cat){
$sql .= ($i == 0) ? ' AND ' : ' OR ';
$sql .= 'cat = "' . $cat . '"';
$i++;
}
}
echo $sql;
/* Output: SELECT FROM shop WHERE title LIKE '%PHP%' AND cat = "boeken" OR cat = "cds" */
}
?>
<form method="POST">
<input type="search" name="q" /><br />
<label>Boeken</label>
<input type="checkbox" name="cat[]" value="boeken" />
<label>CD's</label>
<input type="checkbox" name="cat[]" value="cds" />
<label>Games</label>
<input type="checkbox" name="cat[]" value="games" />
<button>Zoeken</button>
</form>
Edit:
Kleine aanpassing in het script
Aanpassing betreft reactie van Erwin
Aanpassing betreft reactie van Erwin
Gewijzigd op 18/12/2013 15:05:39 door Michael -
Correctie: de LIKE was voor de titel, niet voor de categorie.
Gewijzigd op 18/12/2013 14:53:42 door Erwin H
Erwin H op 18/12/2013 14:52:38:
Behalve dan dat je niet AND moet gebruiken in je query, maar OR. Anders kan je wel op "boeken" AND "games" zoeken, maar dan krijg je waarschijnlijk niet veel terug, aangezien het meestal een boek of game is.
Daarbij zou ik ook geen LIKE gebruiken, tenzij je erg onvoorstandig meerdere categorie opties in 1 databaseveld propt.
Correctie: de LIKE was voor de titel, niet voor de categorie.
Correctie: de LIKE was voor de titel, niet voor de categorie.
Je hebt gelijkt. De eerste moet AND zijn, maar de daaropvolgende moet OR zijn. De code is hierop aangepast.
Dus bijvoorbeeld een flesje water die in de kerst en in de zomer verkocht kan worden, wordt niet getoond. Dus niet alle andere producten die of alleen in de zomer of alleen in de kerst worden getoond.
Gewijzigd op 18/12/2013 15:27:27 door Orlando Smits
Is het geen optie om voor elke checkbox die er is een query uit te voeren? Zou met behulp van een loopje vrij weinig code moeten zijn (over snelheid ga ik niet spreken)
Laat anders wat relevante code zien.
FROM `product` , `categorie` , `categorie_product`
WHERE `product` . `product_id` = `categorie_product`. `product_id`
AND `categorie`.`categorie_id` = `categorie_product`.`categorie_id`
AND `categorie`.`naam` = 'Zomer'
AND `categorie`.`naam` = 'Winter'
Tabellen:
Product (staan producten in)
Categorie (staan de categorieen in)
categorie_product (koppeltabel voor product en categorie)
Orlando Smits op 18/12/2013 15:35:23:
SELECT `product`.`product_id` , `product`.`naam` , `product`.`prijs` , `product`.`omschrijving` , `product`.`voorraad`
FROM `product` , `categorie` , `categorie_product`
WHERE `product` . `product_id` = `categorie_product`. `product_id`
AND `categorie`.`categorie_id` = `categorie_product`.`categorie_id`
AND `categorie`.`naam` = 'Zomer'
AND `categorie`.`naam` = 'Winter'
Tabellen:
Product (staan producten in)
Categorie (staan de categorieën in)
categorie_product (koppeltabel voor product en categorie)
SELECT `product`.`product_id` , `product`.`naam` , `product`.`prijs` , `product`.`omschrijving` , `product`.`voorraad`
FROM `product` , `categorie` , `categorie_product`
WHERE `product` . `product_id` = `categorie_product`. `product_id`
AND `categorie`.`categorie_id` = `categorie_product`.`categorie_id`
AND `categorie`.`naam` = 'Zomer'
AND `categorie`.`naam` = 'Winter'
Tabellen:
Product (staan producten in)
Categorie (staan de categorieën in)
categorie_product (koppeltabel voor product en categorie)
Je hebt nu zomer AND winter, dus alle resultaten die in beide categorieën voorkomen.
Wil je dus ook producten die maar in 1 van de 2 categorieën voorkomt moet je de laatste wijzigen in OR.
WHERE `product` . `product_id` = `categorie_product`. `product_id`
AND `categorie`.`categorie_id` = `categorie_product`.`categorie_id`
AND `categorie`.`naam` = 'Zomer'
OR `categorie`.`naam` = 'Winter'
Edit:
Beter is denk ik nog om zomer en winter tussen haakjes te plaatsen
AND (`categorie`.`naam` = 'Zomer'
OR `categorie`.`naam` = 'Winter')
AND (`categorie`.`naam` = 'Zomer'
OR `categorie`.`naam` = 'Winter')
Gewijzigd op 18/12/2013 15:42:02 door Michael -
Dit lijkt mij een typisch voorbeeld van een meer op meer relatie, en dus zou er een linktabel moeten bestaan om de producten aan meerdere categorieën te kunnen koppelen.
Overigens is het een stuk eenvoudiger om WHERE ... IN te gebruiken dan elke keer ... = ... OR ... = ... te doen.
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
SELECT a.product_id, a.naam, a.prijs, a.omschrijving, a.voorraad
FROM product a
LEFT JOIN categorie_product b ON a.product_id = b.product_id
LEFT JOIN categorie c ON b.categorie_id = c.categorie_id
WHERE c.naam IN ('zomer', 'winter')
GROUP BY a.product_id, a.naam, a.prijs, a.omschrijving, a.voorraad
HAVING COUNT(*) = 2;
FROM product a
LEFT JOIN categorie_product b ON a.product_id = b.product_id
LEFT JOIN categorie c ON b.categorie_id = c.categorie_id
WHERE c.naam IN ('zomer', 'winter')
GROUP BY a.product_id, a.naam, a.prijs, a.omschrijving, a.voorraad
HAVING COUNT(*) = 2;
Als je de having clause op 2 zet krijg je alleen de resultaten die aan alle categorieen voldoen, zet je het op >= 1 dan krijg je alle die 1 of meer hebben.
Gewijzigd op 18/12/2013 15:58:06 door Erwin H
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$sql = "SELECT product_id, p.product_name, p.product_price
FROM product p
JOIN categorie_product c USING (product_id)
WHERE c.categorie_id IN (" . implode(',', $_POST['categorie'] . ')';
?>
$sql = "SELECT product_id, p.product_name, p.product_price
FROM product p
JOIN categorie_product c USING (product_id)
WHERE c.categorie_id IN (" . implode(',', $_POST['categorie'] . ')';
?>
Ger, merk wel op dat je zo resultaten dubbel kunt krijgen.
SELECT `product`.`product_id` , `product`.`naam` , `product`.`prijs` , `product`.`omschrijving` , `product`.`voorraad`
FROM `product` , `categorie` , `categorie_product`
WHERE `categorie`.`naam` IN ('Zomer', 'winter')
AND `product` . `product_id` = `categorie_product`. `product_product_id`
AND`categorie`.`categorie_id` = `categorie_product`.`categorie_categorie_id`
GROUP BY naam
En natuurlijk iedereen bedankt voor de hulp!
Gewijzigd op 18/12/2013 16:00:05 door Orlando Smits
Idd Erwin, was de DISTINCT vergeten
Gewijzigd op 18/12/2013 16:02:23 door Erwin H
Je gebruikt group_by zonder aggegrate functie, dus heb je hem niet nodig, en het maakt de query alleen maar trager.
Erwin H op 18/12/2013 16:01:54:
@Orlando: Weet wel dat je een foute GROUP BY clause hebt. Als je docent een pietje precies is zal hij je daarop aanspreken. In een GROUP BY moeten in principe alle non-aggregate kolommen uit de select. In jouw geval dus allemaal.
Oke dan hebben we hem aangepast, Bedankt!