这个Mysql查询有什么问题

时间:2016-10-02 13:14:04

标签: mysql select

我的项目中遇到了mysql查询问题。

有3个表名为product,product_option,product_category

这是product_option的数据:

mysql> select * from product_option where product_id = 2;
+-------------------+------------+
| product_option_id | product_id |
+-------------------+------------+
|                 2 |          2 |
|                 3 |          2 |
|                 4 |          2 |
+-------------------+------------+
3 rows in set (0.00 sec)

这是product_category的数据:

mysql> select * from product_category where product_id = 2;
+-------------+------------+
| category_id | product_id |
+-------------+------------+
|          15 |          2 |
|           2 |          2 |
|           4 |          2 |
+-------------+------------+
3 rows in set (0.00 sec)

现在我想选择具有这些选项和类别的产品。

这是我试过的方式。但它给了9排。 (它重复了category_id和option_id 3次)

mysql> SELECT p.product_id
    ->      , p.product_name
    ->      , p.enabled
    ->      , p.date_available
    ->      , pc.category_id
    ->      , po.product_option_id
    -> FROM  product p
    -> INNER JOIN `product_category` pc USING(product_id)
    -> LEFT JOIN `product_option` po USING(product_id)
    -> WHERE p.product_id = 2;
+------------+--------------+---------+----------------+-------------+-------------------+
| product_id | product_name | enabled | date_available | category_id | product_option_id |
+------------+--------------+---------+----------------+-------------+-------------------+
|          2 | dsfad        |       1 | 2016-10-18     |          15 |                 2 |
|          2 | dsfad        |       1 | 2016-10-18     |           2 |                 2 |
|          2 | dsfad        |       1 | 2016-10-18     |           4 |                 2 |
|          2 | dsfad        |       1 | 2016-10-18     |          15 |                 3 |
|          2 | dsfad        |       1 | 2016-10-18     |           2 |                 3 |
|          2 | dsfad        |       1 | 2016-10-18     |           4 |                 3 |
|          2 | dsfad        |       1 | 2016-10-18     |          15 |                 4 |
|          2 | dsfad        |       1 | 2016-10-18     |           2 |                 4 |
|          2 | dsfad        |       1 | 2016-10-18     |           4 |                 4 |
+------------+--------------+---------+----------------+-------------+-------------------+
9 rows in set (0.00 sec)

我也试过这样的事情:

SELECT p.product_id
     , p.product_name
     , p.description
     , p.meta_title
     , p.meta_description
     , p.meta_key_word
     , p.brand
     , p.quantity
     , p.price
     , p.enabled
     , p.date_available
     , pc.category_id
     , po.product_option_id
FROM  product p
INNER JOIN (
          SELECT product_id, category_id
          FROM   product_category
          GROUP  BY product_id
          ) pc ON pc.product_id = p.product_id
LEFT JOIN (
          SELECT product_id, product_option_id
          FROM   product_option
          GROUP  BY product_id
          ) po ON po.product_id = p.product_id
WHERE p.product_id = 2\G

但是对我来说都不适用。 谁能告诉我这个问题会是什么?

谢谢。

3 个答案:

答案 0 :(得分:1)

其他人已回答您正在获得Cartesian product产品选项和产品类别。这是您问题的答案"此查询的问题是什么?"

您可能还想知道如何更改查询,以便它返回笛卡尔积。我可以想到两个解决方案:

  1. 为每个联接执行一个查询,并且不要尝试将它们组合到一个查询中。您将获得两个结果集,然后您必须在应用程序代码中获取这些结果集并将其合并到您想要表示一个"产品"对象

    SELECT p.product_id
         , p.product_name
         , p.description
         , p.meta_title
         , p.meta_description
         , p.meta_key_word
         , p.brand
         , p.quantity
         , p.price
         , p.enabled
         , p.date_available
         , pc.category_id
    FROM  product p
    INNER JOIN (
              SELECT product_id, category_id
              FROM   product_category
              GROUP  BY product_id
              ) pc ON pc.product_id = p.product_id
    WHERE p.product_id = 2
    
    SELECT p.product_id
         , po.product_option_id
    FROM  product p
    LEFT JOIN (
              SELECT product_id, product_option_id
              FROM   product_option
              GROUP  BY product_id
              ) po ON po.product_id = p.product_id
    WHERE p.product_id = 2
    
  2. 您可能会想,"我必须在一个查询中获取所有数据,因为我使用的是需要它的编程工具或框架!"这不是一个好理由。许多域对象需要多个SQL查询才能获取其所有数据。如果您使用的框架不支持实际应用程序,那么您应该更改框架。

    1. 将每个连接表的结果减少到一行,这样笛卡尔积只能乘以1x1行。

      SELECT p.product_id
           , p.product_name
           , p.description
           , p.meta_title
           , p.meta_description
           , p.meta_key_word
           , p.brand
           , p.quantity
           , p.price
           , p.enabled
           , p.date_available
           , GROUP_CONCAT(pc.category_id) AS category_id_list
           , GROUP_CONCAT(po.product_option_id) AS product_option_id_list
      FROM  product p
      INNER JOIN (
                SELECT product_id, category_id
                FROM   product_category
                GROUP  BY product_id
                ) pc ON pc.product_id = p.product_id
      LEFT JOIN (
                SELECT product_id, product_option_id
                FROM   product_option
                GROUP  BY product_id
                ) po ON po.product_id = p.product_id
      WHERE p.product_id = 2
      GROUP BY p.product_id
      
      +------------+--------------+---------+----------------+-------------+-------------------+
      | product_id | product_name | enabled | date_available | category_id | product_option_id |
      +------------+--------------+---------+----------------+-------------+-------------------+
      |          2 | dsfad        |       1 | 2016-10-18     |      2,4,15 |             2,3,4 |
      +------------+--------------+---------+----------------+-------------+-------------------+
      
    2. 此解决方案将类别和产品选项列表作为逗号分隔的字符串返回,而不是单个项目,因此获取结果的应用程序代码必须将字符串拆分为其元素。

答案 1 :(得分:0)

有谁可以告诉我这个问题是什么?

我在你的帖子中回答了这个问题。此行为是预期的,您的查询是正确的。您正在获得具有类别和选项的笛卡尔积,因为它们之间没有关系。

所以你有1个产品,3个选项和3个类别。您的查询正在为每个唯一对生成行,因此您的输出中会得到1*3*3 = 9行。

答案 2 :(得分:0)

  1. 您的查询没有问题。结果也是正确的 您的查询。
  2. 结果中没有重复的行。你的结果 包含9行,包含9种不同的category_id和 product_option_id。例如,您有3行具有相同的category_id = 15以及3个不同的product_option_id值2,3,4。
    • 15,2
    • 15,3
    • 15,4