Если у вас есть неизвестное количество опций, вы можете использовать хранимую процедуру для динамического создания запроса, который можно использовать для поворота вашей таблицы. Примерно так:
CREATE PROCEDURE display_options()
BEGIN
SET @query = 'SELECT p.id, ';
SET @query = CONCAT(@query, (SELECT GROUP_CONCAT(CONCAT('MAX(CASE WHEN o.name = ''', name, ''' THEN o.name END) AS `', name, '`')) FROM options ORDER BY id));
SET @query = CONCAT_WS(' ', @query,
'FROM products p',
'JOIN product_options po ON po.product_id = p.id',
'JOIN options o ON o.id = po.option_id',
'GROUP BY p.id');
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Эта процедура создаст запрос, подобный этому (по сути, такой же, как в ответе @ GordonLinoff для данных примера в вашем вопросе):
SELECT p.name,
MAX(CASE WHEN o.name = 'Option 1' THEN o.name END) AS `Option 1`,
MAX(CASE WHEN o.name = 'Option 2' THEN o.name END) AS `Option 2`,
MAX(CASE WHEN o.name = 'Option 3' THEN o.name END) AS `Option 3`,
MAX(CASE WHEN o.name = 'Option 4' THEN o.name END) AS `Option 4`,
MAX(CASE WHEN o.name = 'Option 5' THEN o.name END) AS `Option 5`
FROM products p
JOIN product_options po ON po.product_id = p.id
JOIN options o ON o.id = po.option_id
GROUP BY p.name
, который затем можно подготовить и выполнить для получения таких результатов:
name Option 1 Option 2 Option 3 Option 4 Option 5
Product 1 Option 1 Option 2 Option 3
Product 2 Option 2 Option 3 Option 4
Product 3 Option 3 Option 4 Option 5
демо на dbfiddle