I'm hoping someone could help me with this problem.
Say I have 3 DB tables:
Users:
user_id, user_name
100, John
101, Jessica
Cars:
car_id, car_name
30, Corvette
31, BMW
UsersCars:
user_id, car_id, car_colour
100, 30, Red
101, 30, Green
101, 31, Green
(so John got a red corvette and Jessica has a green Corvette and a BMW)
I would like to have code that returns a multidimensional PHP array something like:
Array
(
[100] => Array
(
[user_id] => 100
[user_name] => John
[cars] => Array
(
[car_id]=>30,
[car_name]=>'Corvette',
[car_colour]=>'Red'
)
)
[101] => Array
(
[user_id] => 101
[user_name] => Jessica
[cars] => Array
(
[0] => Array
(
[car_id]=>30,
[car_name]=>'Corvette',
[car_colour]=>'Green'
),
[1] => Array
(
[car_id]=>31,
[car_name]=>'BMW',
[car_colour]=>'Green'
)
)
)
)
I have the following SQL
SELECT u.*, c.* FROM Users u
LEFT JOIN UsersCars uc ON u.user_id = uc.user_id
LEFT JOIN Cars c ON uc.car_id = c.car_id
And PHP
$result = mysqli_query($db, $q);
while ($row = mysqli_fetch_assoc($result)) {
$users_with_cars[$row['user_id']] = $row;
}
But this isn't correct. Anyone knows how to solve this resulting the above array (with performance in mind)? I rather do not want to hard-coded the exception of "cars" being something that can happen more than once. I rather have something that just looks at $row and $users_with_cars and when seeing some new value, it appends it, by converting the old value into an array. Maybe there's already a native PHP function for this? Or better, maybe my MySQL or whole approach is wrong?
Any help or tips appreciated.
Regards
UPDATE SOLVED
Here's an update, maybe I can help someone else how I solved it eventually.
I ended up with always using an array for one or more cars, and I adjusted the tables to always have an "id" as column name. This way you can easily expand it. See example;
Users:
id, name
100, John
101, Jessica
Cars:
id, name
30, Corvette
31, BMW
UsersCars:
user_id, car_id, car_colour
100, 30, Red
101, 30, Green
101, 31, Green
$q = 'SELECT u.*, c.id as car_id, c.name as car_name, uc.colour as car_colour FROM Users u
LEFT JOIN UsersCars uc ON u.id = uc.user_id
LEFT JOIN Cars c ON uc.car_id = c.id';
$result = mysqli_query($db, $q);
while ($row = mysqli_fetch_assoc($result)) {
$users_with_cars[] = $row;
}
$joins = array('cars' => array('car_id'=>'id','car_name'=>'name','car_colour'=>'colour'));
$users_with_cars = create_join_array($users_with_cars, $joins);
print_r($users_with_cars);
function create_join_array($rows, $joins){
/* build associative multidimensional array with joined tables from query rows */
foreach((array)$rows as $row){
if (!isset($out[$row['id']])) {
$out[$row['id']] = $row;
}
foreach($joins as $name => $item){
unset($newitem);
foreach($item as $field => $newfield){
unset($out[$row['id']][$field]);
if (!empty($row[$field]))
$newitem[$newfield] = $row[$field];
}
if (!empty($newitem))
$out[$row['id']][$name][$newitem[key($newitem)]] = $newitem;
}
}
return $out;
}
This all results in the beautiful array:
Array
(
[100] => Array
(
[id] => 100
[name] => John
[cars] => Array
(
[30] => Array
(
[id]=>30
[name]=>'Corvette',
[colour]=>'Red'
)
)
)
[101] => Array
(
[id] => 101
[name] => Jessica
[cars] => Array
(
[30] => Array
(
[id]=>30,
[name]=>'Corvette',
[colour]=>'Green'
),
[31] => Array
(
[id]=>31,
[name]=>'BMW',
[colour]=>'Green'
)
)
)
)
Let's say the users also can have multiple bikes. Then, you have multiple join arrays, you can easily bind on with left joins and add it to the join array.
$q = 'SELECT u.*, c.id as car_id, c.name as car_name, uc.colour as car_colour, b.id as bike_id, b.name as bike_name FROM Users u
LEFT JOIN UsersCars uc ON u.user_id = uc.user_id
LEFT JOIN Cars c ON uc.car_id = c.id
LEFT JOIN UsersBikes ub ON u.user_id = ub.user_id
LEFT JOIN Bikes b ON ub.bike_id = b.id';
$result = mysqli_query($db, $q);
while ($row = mysqli_fetch_assoc($result)) {
$users_with_cars_bikes[] = $row;
}
$joins = array('cars' => array('car_id'=>'id', 'car_name'=>'name', 'car_colour'=>'colour'),
'bikes' => array('bike_id'=>'id', 'bike_name'=>'name'));
$users_with_cars_bikes = create_join_array($users_with_cars_bikes, $joins);
print_r($users_with_cars_bikes);
Would result in something like
Array(
[100] => Array
(
[id] => 100
[name] => John
[cars] => Array
(
[30] => Array
(
[id]=>30
[name]=>'Corvette',
[colour]=>'Red'
)
)
[bikes] => Array
(
[41] => Array
(
[id]=>41
[name]=>'BMX'
)
)
)
)
and so on..
Thanks all for helping out :)
[cars]array) I just get annoyed about some web service that returns a specific variable once as single string or array and in another result set as an array of arrays. Thus I need to check each value on client if it has more children or not. It would be easier to read the data again if you have a data structure that didn't change for different result sets. So your[cars]array should always contain a "parent" array for any cars, even with a single entry(array) new StdClass()also returns an array. But what you will get is not an array containing a single object (array( new StdClass() )), but the object's members in an array.