Σύνδεση μέσω πίνακα σύνδεσης στην PHP
Ας υποθέσουμε τώρα ότι ο χρήστης βρισκόταν σε διαφορετικές πόλεις. Σε αυτή την περίπτωση ο πίνακας με τους χρήστες θα μπορούσε να έχει την ακόλουθη μορφή:
| id | name | city |
|---|---|---|
| 1 | user1 | city1, city2, city3 |
| 2 | user2 | city1, city2 |
| 3 | user3 | city2, city3 |
| 4 | user4 | city1 |
Είναι σαφές ότι η αποθήκευση δεδομένων με αυτόν τον τρόπο είναι λανθασμένη - οι πόλεις πρέπει να μεταφερθούν σε ξεχωριστό πίνακα. Αυτός είναι:
| id | name |
|---|---|
| 1 | city1 |
| 2 | city2 |
| 3 | city3 |
Ωστόσο, πρέπει να καταφέρουμε κάθε χρήστης να μπορεί να αναφέρεται σε πολλές πόλεις. Με δύο πίνακες αυτό είναι αδύνατο.
Χρειαζόμαστε να εισάγουμε τον λεγόμενο πίνακα σύνδεσης, ο οποίος θα συνδέει τον χρήστη με τις πόλεις του.
Σε κάθε εγγραφή αυτού του πίνακα θα αποθηκεύεται μια σύνδεση μεταξύ ενός χρήστη και μιας πόλης. Ενώ για έναν χρήστη σε αυτόν τον πίνακα θα υπάρχουν τόσες εγγραφές, όσες πόλεις έχει επισκεφτεί.
Αυτός είναι ο πίνακας σύνδεσής μας:
| id | user_id | city_id |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 3 | 2 |
| 7 | 3 | 3 |
| 8 | 4 | 1 |
Ο πίνακας με τους χρήστες θα αποθηκεύει μόνο τα ονόματα των χρηστών, χωρίς συνδέσεις:
| id | name |
|---|---|
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
| 4 | user4 |
| 5 | user5 |
Ερωτήματα
Ας κάνουμε ένα ερώτημα, με το οποίο θα ανακτήσουμε τους χρήστες μαζί με τις πόλεις τους. Για αυτό θα χρειαστούμε να κάνουμε δύο ενώσεις: η πρώτη ένωση θα ενώσει στους χρήστες τον πίνακα σύνδεσης, και η δεύτερη ένωση μέσω των συνδέσεων θα ενώσει τις πόλεις:
SELECT
users.name as user_name, cities.name as city_name
FROM
users
LEFT JOIN users_cities ON users_cities.user_id=users.id
LEFT JOIN cities ON users_cities.city_id=cities.id
Αποτέλεσμα ερωτήματος
Το αποτέλεσμα του ερωτήματός μας στην PHP θα περιέχει το όνομα κάθε χρήστη τόσες φορές, με πόσες πόλεις είναι συνδεδεμένος:
<?php
$arr = [
['user_name' => 'user1', 'city_name' => 'city1'],
['user_name' => 'user1', 'city_name' => 'city2'],
['user_name' => 'user1', 'city_name' => 'city3'],
['user_name' => 'user2', 'city_name' => 'city1'],
['user_name' => 'user2', 'city_name' => 'city2'],
['user_name' => 'user3', 'city_name' => 'city2'],
['user_name' => 'user3', 'city_name' => 'city3'],
['user_name' => 'user4', 'city_name' => 'city1'],
];
?>
Θα ήταν πιο βολικό να μετατραπεί ένας τέτοιος πίνακας και να μετασχηματιστεί στον ακόλουθο:
<?php
$res = [
['user1' => ['city1', 'city2', 'city3']],
['user2' => ['city1', 'city2']],
['user3' => ['city2', 'city3']],
['user4' => ['city1']],
];
?>
Ας γράψουμε κώδικα που εκτελεί μια τέτοια μετατροπή:
<?php
$res = [];
foreach ($data as $elem) {
$res[$elem['user_name']][] = $elem['city_name'];
}
var_dump($res);
?>
Πρακτικές ασκήσεις
Ας υποθέσουμε ότι ένα προϊόν μπορεί να ανήκει σε πολλές κατηγορίες. Περιγράψτε τη δομή αποθήκευσης.
Γράψτε ένα ερώτημα που θα ανακτά τα προϊόντα μαζί με τις κατηγορίες τους.
Εμφανίστε τα ληφθέντα δεδομένα ως μια λίστα
ul έτσι ώστε σε κάθε li στην αρχή
να βρίσκεται το όνομα του προϊόντος, και μετά την άνω και κάτω τελεία μέσω
κόμμα να αναγράφονται οι κατηγορίες αυτού του προϊόντος.
Περίπου έτσι:
<ul>
<li>product1: category1, category2, category3</li>
<li>product2: category1, category3</li>
<li>product3: category1</li>
</ul>