You are probably using mysqli_result::fetch_assoc
to return each row of your result set as an associative array. MySQL will let you have two columns with the same name in a query, but these do not map to an associative array the way you want them to—even though the associative array is doing exactly as it should.
Assume two tables, book
and author
, linked by the junction table book_author
. In MySQL, you can run the following query, which returns two id
columns:
SELECT b.*, a.*
FROM book AS b
JOIN book_author AS ba ON ba.book_id = b.id
JOIN author AS a ON a.id = ba.author_id
LIMIT 2;
+----+-----------------+----+--------------+
| id | title | id | name |
+----+-----------------+----+--------------+
| 1 | Design Patterns | 1 | Erich Gamma |
| 1 | Design Patterns | 2 | Richard Helm |
+----+-----------------+----+--------------+
If you try to map one of these rows to an associative array, you end up with a single id
element in your array:
$row = $result->fetch_assoc();
print_r($row);
Array
(
[id] => 1
[title] => Design Patterns
[name] => Erich Gamma
)
The last id
column in the row will overwrite any that precede it. Here’s the second row from the result set:
Array
(
[id] => 2
[title] => Design Patterns
[name] => Richard Helm
)
This is just the same as modifying the value of an element in an associative array;
$row = array();
$row['id'] = 1;
print_r($row);
Array
(
[id] => 1
)
$row['id'] = 2;
print_r($row);
Array
(
[id] => 2
)
If you give each column a unique name in your query, either by doing so in the table itself, or giving it an alias in the query, the problem is avoided:
SELECT b.id AS book_id, b.title,
a.id AS author_id, a.name
FROM book AS b
JOIN book_author AS ba ON ba.book_id = b.id
JOIN author AS a ON a.id = ba.author_id
LIMIT 2;
+---------+-----------------+-----------+--------------+
| book_id | title | author_id | name |
+---------+-----------------+-----------+--------------+
| 1 | Design Patterns | 1 | Erich Gamma |
| 1 | Design Patterns | 2 | Richard Helm |
+---------+-----------------+-----------+--------------+
$row = $result->fetch_assoc();
print_r($row);
Array
(
[book_id] => 1
[title] => Design Patterns
[author_id] => 1
[name] => Erich Gamma
)
Alternatively, you could (and almost certainly should) use prepared statements instead. Although this can get round the problem of duplicate column names, using unique column names in your queries still makes things much easier to read and debug:
$sql = 'SELECT b.*, a.* ' .
'FROM book AS b ' .
'JOIN book_author AS ba ' .
'ON ba.book_id = b.id ' .
'JOIN author AS a ' .
'ON a.id = ba.author_id';
$stmt = $mysqli->prepare($sql);
$stmt->execute();
$stmt->bind_result($book_id, $book_title, $author_id, $author_name);
while ($stmt->fetch()) {
printf("%s, %s, %s, %s\n",
$book_id,
$book_title,
$author_id,
$author_name);
}