SQL-如何显示产品的选项,无论它们是否具有选项?

时间:2019-01-22 01:36:52

标签: mysql sql pivot-table entity-attribute-value

假设一个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:我事先不知道这些选项可能是什么。而且,产品可能具有的选择数量没有限制。

5 个答案:

答案 0 :(得分:3)

如果选项数量未知,则可以使用存储过程动态创建可用于旋转表的查询。像这样:

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

demo on dbfiddle

答案 1 :(得分:3)

经过如此多的试验,我发现以下查询将返回所需的准确结果,即使选项和产品可能增加。

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

答案 2 :(得分:2)

如果我理解正确,则可以使用条件聚合:

[a-zA-Z0-9]{3,20}@[a-zA-Z0-9]{3,20}\.[a-zA-Z0-9]{3,20}

答案 3 :(得分:1)

您是否真的需要在数据库级别构建显示?

老实说,如果一切可行,我会节省自己的头绪,然后奔跑:

  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 ...

然后在遍历结果集时可以在应用程序级别整理所需的结构

答案 4 :(得分:0)

您可以创建一个具有product_count行×option_count行的结果集,而不是使用具有product_count行×option_count列的结果集:

SELECT products.name
     , options.name
     , CASE WHEN product_options.id IS NOT NULL THEN 'Y' END
FROM products
CROSS JOIN options
LEFT JOIN product_options ON products.id = product_options.product_id AND options.id = product_options.option_id

结果集将包含产品和选项的所有组合,第三列将包含NULL或Y