In dieser Demo filtern wir Produkte anhand gewählter Kategorien.
Die zugehörige Kategorie wird per LEFT JOIN
eingeblendet – auch wenn keine passende Kategorie vorhanden ist.
Besonderheit: Unsere JOIN-Funktion unterstützt auch unterschiedlich benannte Felder.
Statt dass in beiden Tabellen die Spalte gleich heißt (z. B. category_id
),
können wir gezielt angeben, welche Felder verknüpft werden sollen – mit:
->join('st3_categories', ['local' => 'pro_cat_id', 'foreign' => 'cat_id'], 'LEFT')
🔄 local
bezeichnet das Feld in der aktuellen Tabelle („Produkte“),
🆚 foreign
das Feld in der verknüpften Tabelle („Kategorien“).
Damit funktioniert der JOIN auch dann, wenn die Feldnamen nicht übereinstimmen – z. B. pro_cat_id
⇄ cat_id
.
Produkt | Kategorie | Preis |
---|---|---|
Produkt 1 | Technik | 💶 29.40 € |
Produkt 10 | Technik | 💶 24.30 € |
Produkt 11 | Büro | 💶 48.40 € |
Produkt 12 | Büro | 💶 83.20 € |
Produkt 13 | Freizeit | 💶 15.00 € |
Produkt 14 | Gesundheit | 💶 96.90 € |
Produkt 15 | Gesundheit | 💶 59.70 € |
Produkt 16 | Freizeit | 💶 95.20 € |
Produkt 17 | Gesundheit | 💶 59.00 € |
Produkt 18 | Haushalt | 💶 61.70 € |
Produkt 19 | Technik | 💶 15.70 € |
Produkt 2 | Haushalt | 💶 86.20 € |
Produkt 20 | Haushalt | 💶 95.10 € |
Produkt 21 | Freizeit | 💶 23.90 € |
Produkt 22 | Technik | 💶 99.00 € |
Produkt 23 | Haushalt | 💶 78.20 € |
Produkt 24 | Büro | 💶 71.40 € |
Produkt 25 | Freizeit | 💶 55.60 € |
Produkt 3 | Technik | 💶 42.00 € |
Produkt 4 | Technik | 💶 17.10 € |
Produkt 5 | Technik | 💶 30.40 € |
Produkt 6 | Haushalt | 💶 73.00 € |
Produkt 7 | Technik | 💶 96.30 € |
Produkt 8 | Haushalt | 💶 45.70 € |
Produkt 9 | Haushalt | 💶 52.30 € |
[
{
"cat_id": 1,
"cat_title": "B\u00fcro"
},
{
"cat_id": 2,
"cat_title": "Technik"
},
{
"cat_id": 3,
"cat_title": "Haushalt"
},
{
"cat_id": 4,
"cat_title": "Freizeit"
},
{
"cat_id": 5,
"cat_title": "Gesundheit"
}
]
[
{
"pro_id": 1,
"pro_title": "Produkt 1",
"pro_price": 29.4,
"pro_cat_id": 2
},
{
"pro_id": 2,
"pro_title": "Produkt 2",
"pro_price": 86.2,
"pro_cat_id": 3
},
{
"pro_id": 3,
"pro_title": "Produkt 3",
"pro_price": 42,
"pro_cat_id": 2
},
{
"pro_id": 4,
"pro_title": "Produkt 4",
"pro_price": 17.1,
"pro_cat_id": 2
},
{
"pro_id": 5,
"pro_title": "Produkt 5",
"pro_price": 30.4,
"pro_cat_id": 2
},
{
"pro_id": 6,
"pro_title": "Produkt 6",
"pro_price": 73,
"pro_cat_id": 3
},
{
"pro_id": 7,
"pro_title": "Produkt 7",
"pro_price": 96.3,
"pro_cat_id": 2
},
{
"pro_id": 8,
"pro_title": "Produkt 8",
"pro_price": 45.7,
"pro_cat_id": 3
},
{
"pro_id": 9,
"pro_title": "Produkt 9",
"pro_price": 52.3,
"pro_cat_id": 3
},
{
"pro_id": 10,
"pro_title": "Produkt 10",
"pro_price": 24.3,
"pro_cat_id": 2
},
{
"pro_id": 11,
"pro_title": "Produkt 11",
"pro_price": 48.4,
"pro_cat_id": 1
},
{
"pro_id": 12,
"pro_title": "Produkt 12",
"pro_price": 83.2,
"pro_cat_id": 1
},
{
"pro_id": 13,
"pro_title": "Produkt 13",
"pro_price": 15,
"pro_cat_id": 4
},
{
"pro_id": 14,
"pro_title": "Produkt 14",
"pro_price": 96.9,
"pro_cat_id": 5
},
{
"pro_id": 15,
"pro_title": "Produkt 15",
"pro_price": 59.7,
"pro_cat_id": 5
},
{
"pro_id": 16,
"pro_title": "Produkt 16",
"pro_price": 95.2,
"pro_cat_id": 4
},
{
"pro_id": 17,
"pro_title": "Produkt 17",
"pro_price": 59,
"pro_cat_id": 5
},
{
"pro_id": 18,
"pro_title": "Produkt 18",
"pro_price": 61.7,
"pro_cat_id": 3
},
{
"pro_id": 19,
"pro_title": "Produkt 19",
"pro_price": 15.7,
"pro_cat_id": 2
},
{
"pro_id": 20,
"pro_title": "Produkt 20",
"pro_price": 95.1,
"pro_cat_id": 3
},
{
"pro_id": 21,
"pro_title": "Produkt 21",
"pro_price": 23.9,
"pro_cat_id": 4
},
{
"pro_id": 22,
"pro_title": "Produkt 22",
"pro_price": 99,
"pro_cat_id": 2
},
{
"pro_id": 23,
"pro_title": "Produkt 23",
"pro_price": 78.2,
"pro_cat_id": 3
},
{
"pro_id": 24,
"pro_title": "Produkt 24",
"pro_price": 71.4,
"pro_cat_id": 1
},
{
"pro_id": 25,
"pro_title": "Produkt 25",
"pro_price": 55.6,
"pro_cat_id": 4
}
]
<?php
// Seitentitel und Includes
$pageTitle = "JsonSQL Demo: WHERE IN Filter mit JOIN & Alias";
$JsonSQLpath = __DIR__ . '/../../src/JsonSQL.php';
if (!file_exists($JsonSQLpath)) {
die("❌ Datei nicht gefunden!");
}
require_once $JsonSQLpath;
require_once __DIR__ . '/../includes/header.php';
use Src\JsonSQL;
// JsonSQL-Instanz
$db = new JsonSQL(['demo' => __DIR__ . '/../testdb']);
$db->use('demo');
$categoryTable = 'st3_categories';
$productTable = 'st3_products';
// Demo-Daten vorbereiten
if (!file_exists(__DIR__ . '/../testdb/' . $categoryTable . '.json')) {
$db->truncate($categoryTable);
$cats = ['Büro', 'Technik', 'Haushalt', 'Freizeit', 'Gesundheit'];
foreach ($cats as $i => $cat) {
$db->from($categoryTable)->insert([
'cat_id' => $i + 1,
'cat_title' => $cat
]);
}
}
if (!file_exists(__DIR__ . '/../testdb/' . $productTable . '.json')) {
$db->truncate($productTable);
for ($i = 1; $i <= 25; $i++) {
$db->from($productTable)->insert([
'pro_id' => $i,
'pro_title' => "Produkt $i",
'pro_price' => rand(100, 1000) / 10,
'pro_cat_id' => rand(1, 5)
]);
}
}
// Filter aus der URL
$filterIds = isset($_GET['filter']) ? array_map('intval', $_GET['filter']) : [];
// Kategorien laden
$categories = $db->select('*')->from($categoryTable)->orderBy('cat_title')->get();
// Produkte mit JOIN auf Kategorien – jetzt explizit mit unterschiedlichen Spalten
// !Select am Anfang sonst wird der Filter überschrieben !!!
$db->select([
'pro_title',
'pro_price',
'cat_title'])
->from($productTable,true)
->join($categoryTable, ['local' => 'pro_cat_id', 'foreign' => 'cat_id'], 'LEFT');
if (!empty($filterIds)) {
$db->where([['pro_cat_id', 'IN', $filterIds]]);
}
// Hier Select würde den Filter resetten und wieder alle Datensätze ausgeben
$products = $db->orderBy('pro_title')
->get();
?>
<div class="container">
<h1 class="my-4">🎯 WHERE IN Filter + LEFT JOIN</h1>
<p class="text-muted">
In dieser Demo filtern wir Produkte anhand gewählter Kategorien.<br>
Die zugehörige Kategorie wird per <code>LEFT JOIN</code> eingeblendet – auch wenn keine passende Kategorie vorhanden ist.<br><br>
<strong>Besonderheit:</strong> Unsere JOIN-Funktion unterstützt auch <u>unterschiedlich benannte Felder</u>.<br>
Statt dass in beiden Tabellen die Spalte gleich heißt (z. B. <code>category_id</code>),
können wir gezielt angeben, welche Felder verknüpft werden sollen – mit:
</p>
<pre class="bg-light p-3 rounded">
->join('st3_categories', ['local' => 'pro_cat_id', 'foreign' => 'cat_id'], 'LEFT')
</pre>
<p class="text-muted">
🔄 <code>local</code> bezeichnet das Feld in der aktuellen Tabelle („Produkte“),<br>
🆚 <code>foreign</code> das Feld in der verknüpften Tabelle („Kategorien“).<br>
Damit funktioniert der JOIN auch dann, wenn die Feldnamen nicht übereinstimmen – z. B. <code>pro_cat_id</code> ⇄ <code>cat_id</code>.
</p>
<div class="row mt-4">
<div class="col-md-4">
<div class="card shadow-sm p-3 mb-3">
<h5 class="card-title">📁 Kategorien filtern</h5>
<form method="get">
<?php foreach ($categories as $cat): ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="filter[]" value="<?= $cat['cat_id'] ?>" id="cat<?= $cat['cat_id'] ?>" <?= in_array($cat['cat_id'], $filterIds) ? 'checked' : '' ?>>
<label class="form-check-label" for="cat<?= $cat['cat_id'] ?>">
<?= htmlspecialchars($cat['cat_title']) ?>
</label>
</div>
<?php endforeach; ?>
<div class="d-flex gap-2 mt-3">
<button type="submit" class="btn btn-sm btn-primary">Filter anwenden</button>
<a href="?" class="btn btn-sm btn-outline-secondary">Zurücksetzen</a>
</div>
</form>
</div>
</div>
<div class="col-md-8">
<div class="card shadow-sm p-3">
<h5 class="card-title">📦 Gefilterte Produkte</h5>
<?php if (empty($products)): ?>
<p class="text-muted">Keine Produkte gefunden.</p>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered table-striped align-middle">
<thead class="table-light">
<tr>
<th>Produkt</th>
<th>Kategorie</th>
<th class="text-end">Preis</th>
</tr>
</thead>
<tbody>
<?php foreach ($products as $prod): ?>
<tr>
<td><?= htmlspecialchars($prod['pro_title']) ?></td>
<td><?= isset($prod['cat_title']) ? htmlspecialchars($prod['cat_title']) : '<span class="text-muted">keine Kategorie</span>' ?></td>
<td class="text-end">💶 <?= number_format($prod['pro_price'], 2) ?> €</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php
$scriptName = basename(__FILE__);
// Entferne die Exclude-Tags aus dem Quellcode, aber lasse den eigenen Codeabschnitt aus
$scriptContent = file_get_contents(__FILE__);
// Verhindern, dass der Codeblock selbst ersetzt wird, indem wir ihn in einen temporären Kommentar umwandeln
$scriptContent = preg_replace('//s', '', $scriptContent);
// Hier verwenden wir einen temporären Platzhalter, um den Code zu umgehen, der ersetzt wird.
$scriptContent = str_replace('', '<!-- Exclude End Temp -->', $scriptContent);
?>
<?php
// Vorverarbeitung der Dateien
$jsonCategories = htmlspecialchars(file_get_contents(__DIR__ . '/../testdb/st3_categories.json'));
$jsonProducts = htmlspecialchars(file_get_contents(__DIR__ . '/../testdb/st3_products.json'));
$phpCode = htmlspecialchars($scriptContent); // bereits gesetzt
?>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>