SQL - как отобразить параметры продуктов, есть ли у них они? - PullRequest
0 голосов
/ 22 января 2019

Предположим, что products может иметь 0 или более options - реализовано со следующими таблицами:

products
 - id
 - name

options
 - id
 - name

product_options
 - id
 - product_id
 - option_id

Далее предположим, что следующие продукты имеют следующие параметры:

  • Продукт 1 = Вариант 1, Вариант 2, Вариант 3
  • Продукт 2 = Вариант 2, Вариант 3, Вариант 4
  • Продукт 3 = Вариант 3, Вариант 4, Вариант 5

Как я могу запросить это, чтобы получить такие результаты:

  • Продукт 1, вариант 1, вариант 2, вариант 3, NULL, NULL
  • Продукт 2, NULL, вариант 2, вариант 3, вариант 4, NULL
  • Продукт 3, NULL, NULL, вариант 3, вариант 4, вариант 5

Мои параметры на самом деле являются вложенным деревом. И у них есть внешний ключ к таблице категорий (также вложенное дерево). В конечном итоге мне нужно выполнить этот запрос и сгруппировать результаты по категориям. Однако я, наверное, сначала должен понять, как решить эту более простую версию моей проблемы.

ОБНОВЛЕНИЕ 1: Я заранее не знаю, какие могут быть варианты. Кроме того, количество опций, которые может иметь продукт, не ограничено.

Ответы [ 4 ]

0 голосов
/ 30 января 2019

После стольких испытаний я нашел ниже запрос, который будет возвращать точный результат, как вы хотите, даже если варианты и продукт может увеличиться.

SELECT  CONCAT(P.productName, ",", GROUP_CONCAT(COALESCE(IF(P.optionId IN (product_options.option_id),P.optionName,NULL),"NULL") order by P.optionId)) AS result
FROM product_options
RIGHT JOIN (SELECT products.id as productId,  products.name as productName,options.id as optionId, options.name AS optionName from products,options) 
as P On P.productId = product_options.product_id AND P.optionId = product_options.option_id
GROUP BY P.productId
0 голосов
/ 22 января 2019

Если у вас есть неизвестное количество опций, вы можете использовать хранимую процедуру для динамического создания запроса, который можно использовать для поворота вашей таблицы. Примерно так:

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

0 голосов
/ 24 января 2019

Вам действительно нужно структурировать дисплей на уровне БД?

Честно говоря, если это вообще возможно, я бы спас себе голову и запустил:

  SELECT p.*, o.*
    FROM product_options po
    JOIN products p
      ON p.id = po.product_id
    JOIN options o
      ON o.id = po.option_id
   WHERE ...
ORDER BY ...

Затем вы можете отсортировать желаемую структуру на уровне приложения во время итерации набора результатов

0 голосов
/ 22 января 2019

Вы можете использовать условную агрегацию, если я правильно понимаю:

select po.product_id,
       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 product_options po join
     options o
     on po.option_id = o.id
group by po.product_id
...