2 варианта решения:
1)
Делаем все одним запросом (текущий запрос можете не менять), т.е. у вас будет много строк с одинаковыми product_id (так как таблица product_variants завязана на product, как 1 : M ).
потом на бекенде делаете что-то типо такого:
$prevId = 0;
$resultArr = array();
foreach($result as $row){
if($prevId != $row['product_id'])
{
$resultArr[$row['product_id']] = $row; //сюда ложим поля таблицы product
$resultArr[$row['product_id']]['offers'] = $row['...']//ложим оффер первой строки, если нет- пустой массив
} else
{
$resultArr[$row['product_id']]['offers'] = $row['...']//ложим только необходимые поля
}
$prevId = $row['product_id'];
}
print_r($resultArr);
2)
почти такой же как первый, только в 2 запроса. В 1ом вы достаете все product, во втором product_variants, а после выполнения запроса мержите эти 2 массива по ключу product_id (как в 1ом случае)