简体   繁体   中英

PHP/MySQL: Multiple comma separated values per table field vs... WHAT?

Storing multiple comma-separated values in a single table field is a notoriously bad design as it impacts performance and breaks relationships. Except I don't know how to change things.

I have a movies table:

+------------------------------+
| id |       name       | year |
+------------------------------+
|  1 |       Alien      | 1979 |
|  2 |  Breakfast Club  | 1985 |
|  3 |    First Blood   | 1982 |
+------------------------------+

I need to store the genre(s). I need a separate genres table now that inserting it in the same table is a no-go. But how to structure it? I can only contemplate two ways: using foreign keys or boolean type fields, each with its own pros and cons.

foreign keys :

+---------------------+
| movie_id | genre_id | 
|----------+----------+
|    1     |    2     |
|    1     |    4     |
|    3     |    1     |
+----------+----------|

The problem here is a row per genre penalty. To store more than one genre I have to run multiple insert queries like this:

foreach($genres as $genre_id)
{
    $db->query("INSERT INTO genres (movie_id, genre_id) VALUES ('$movie_id', '$genre_id');
}

Isn't this an excess of db calls? It is the number of introduced genres. How else to do it?

boolean type fields :

+----------+-----------+--------+-------+----------
| movie_id | adventure | comedy | drama | horror  ...
+----------+-----------+--------+-------+----------
|    1     |     0     |   1    |   0   |    1    ...
+----------+-----------+--------+-------+----------
|    3     |     1     |   0    |   0   |    0    ...
+----------+-----------+--------+-------+----------

Is this is better? This will let me run a single insert, except with complex query building:

$query1 = "INSERT INTO genres (movie_id, ";
$query2 = " VALUES ('$movie_id', ";
foreach($genres as $key => $value)
{
    if($value)
    {
        $query1 .= "$key, ";
        $query2 .= "'$value', ";
    }
}
$query = rtrim($query1, ", ") . ")" . rtrim($query2, ", ") . ")";
$db->query($query);

I don't know if this is practical.

I don't like either approach. What is a more elegant solution?

Are you aware a single INSERT statement can insert multiple rows?

INSERT INTO genres (movie_id, genre_id) 
VALUES (?, ?),
       (?, ?),
       (?, ?)...

Alternatively, even if you do one row per call, you can use a prepared statement and execute it multiple times with different values.

$stmt = $db->prepare("INSERT INTO genres (movie_id, genre_id) VALUES (?, ?)");
foreach($genres as $genre_id)
{
    $stmt->execute([$movie_id, $genre_id]);
}

I would not recommend your second solution, storing genres as boolean columns. It's likely that you'll add new genres from time to time, and it's costly to run ALTER TABLE ADD COLUMN every time you do that. Then you need to worry about how many columns is the maximum MySQL can support in a given table, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM