Seostamine läbi seostustabeli PHP-s

Oletame nüüd, et kasutaja on käinud erinevates linnades. Sel juhul võiks kasutajate tabel välja näha järgmine:

users
id name city
1 user1 city1, city2, city3
2 user2 city1, city2
3 user3 city2, city3
4 user4 city1

On selge, et andmeid niimoodi salvestada on vale - linnad tuleks viia eraldi tabelisse. Siin on see:

cities
id name
1 city1
2 city2
3 city3

Siiski peame me tegema nii, et iga kasutaja saaks viidata mitmele linnale. Seda kahe tabeliga teha on võimatu.

Meil on vaja kasutusele võtta nn seostustabel, mis seob kasutaja tema linnadega.

Selle tabeli igas kirjes hoitakse seost kasutaja ja ühe linna vahel. Samas ühe kasutaja jaoks on selles tabelis nii palju kirjeid, kui paljudes linnades ta on käinud.

Siin on meie seostustabel:

users_cities
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

Kasutajate tabel hoiab ainult kasutajate nimesid, ilma seosteta:

users
id name
1 user1
2 user2
3 user3
4 user4
5 user5

Päringud

Teeme päringu, mille abil võtame kasutajad koos nende linnadega. Selleks peame tegema kaks ühendust (JOIN): esimene JOIN ühendab kasutajatega seostustabeli, ja teine JOIN ühendab linnad seoste kaudu:

sqlSELECT
  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

Päringu tulemus

Meie päringu tulemus PHP-s sisaldab iga kasutaja nime nii mitu korda, kui paljude linnadega ta on seotud:

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'],
  ];
?>

Oleks mugavam sellist massiivi ümber teha ja muuta see järgnevasse vormi:

php<?php
  $res = [
    'user1' => ['city1', 'city2', 'city3'],
    'user2' => ['city1', 'city2'],
    'user3' => ['city2', 'city3'],
    'user4' => ['city1'],
  ];
?>

Kirjutame koodi, mis teeb sellise teisenduse:

php<?php
  $res = [];
  
  foreach ($data as $elem) {
    $res[$elem['user_name']][] = $elem['city_name'];
  }
  
  var_dump($res);
?>

Praktilised ülesanded

Задание 1

Oletagem, et toode võib kuuluda mitmesse kategooriasse. Kirjeldage salvestusstruktuuri.

Задание 2

Kirjutage päring, mis võtab tooted koos nende kategooriatega.

Задание 3

Kuva saadud andmed loendina ul nii, et igas li-s oleks algul toote nimi ja peale koolonti loetletud selle toote kategooriad komadega. Umbes nii:

html<ul>
  <li>product1: category1, category2, category3</li>
  <li>product2: category1, category3</li>
  <li>product3: category1</li>
</ul>