【问题标题】:duplicate data being return with varied # of results in cross join交叉连接中返回的重复数据具有不同的结果#
【发布时间】:2020-03-26 05:20:11
【问题描述】:

我为一个服装品牌创建了一个数据库。 products 由 3 个表组成:products、product_photos、inventory。

我遇到的问题与 product_photos 中返回的库存表中的结果数量有关。所以说库存表中应该有 4 个结果(例如尺寸:s、m、l、xl 和数量:20、20、20、20)和 product_photos 表中的 1 个结果(例如照片:url)。在我当前的查询中,product_photos 数据重复了 4 次(例如照片:url、url、url、url)。

我当前的查询如下所示:

SELECT 
  products.id, 
  products.type, 
  products.collection, 
  products.title, 
  products.price, 
  products.thumbnail, 
  GROUP_CONCAT(product_photos.id) AS photoId, 
  GROUP_CONCAT(product_photos.photo) AS photos, 
  GROUP_CONCAT(inventory.size) AS size,                                  
  GROUP_CONCAT(inventory.quantity) as quantity 
FROM `products` 
RIGHT JOIN 
`product_photos` ON products.id = product_photos.product_id 
RIGHT JOIN `inventory` ON products.id = inventory.product_id 
WHERE
products.id = ?
GROUP BY
products.id

我已经尝试过一些事情,例如将右连接更改为内连接和左连接,但右连接似乎是我正在尝试做的技术选择。

这是一些示例数据:

product:
 id: 1

product_photo:
 id: 1,
 product_id: 1,
 photo: url

inventory:
 id: 1,
 product_id: 1,
 size: s,
 quantity: 20

 id: 2,
 product_id: 1,
 size: l,
 quantity: 14

【问题讨论】:

  • 请发布一些示例数据和您预期的输出。
  • ...没有适当的数据样本和表格文本的预期结果,您的问题不清楚..
  • 看到右连接是不寻常的 - 不一定是错的,但我认为在这种情况下左连接更合适
  • 使用左连接不会改变我的结果。不过,我相信你是对的,而且我的脑海里已经把 A 表和 B 表倒过来了。 product_id 在库存中也不是唯一的,因为有多行。我现在将使用示例数据编辑我的帖子

标签: mysql sql node.js


【解决方案1】:

许多结果的原因是product_photos as 和inventory 表都可以有多个相同product_id 的记录,因此两个表中记录的所有成对组合都将被迭代(笛卡尔积) .

您可以通过首先使用 union 从这两个表中选择所有记录,然后将该 结果products 表连接来解决此问题:

SELECT      products.id, 
            products.type, 
            products.collection, 
            products.title, 
            products.price, 
            products.thumbnail,
            GROUP_CONCAT(photoId) AS photoId,
            GROUP_CONCAT(photos) AS photos,
            GROUP_CONCAT(size) AS size,                                  
            GROUP_CONCAT(quantity) as quantity 
FROM        products
LEFT JOIN   (
                SELECT  product_id, 
                        id AS photoId, 
                        photo AS photos,
                        null AS size,
                        null AS quantity
                FROM    product_photos
                UNION
                SELECT  product_id,
                        null,
                        null,
                        size,                                  
                        quantity 
                FROM    inventory 
            ) combi
         ON products.product_id = combi.product_id
WHERE       products.id = ?
GROUP BY    products.id

【讨论】:

  • 有趣的是,在您回答之前,我从未听说过交叉联接/笛卡尔积。感谢您澄清它现在更有意义
【解决方案2】:

这个问题通常会通过沿每个维度独立聚合来处理:

SELECT p.*
       pp.photoIds, pp.photos,
       i.sizes, i.quantitys
FROM products p LEFT JOIN
     (SELECT pp.product_id,
             GROUP_CONCAT(pp.id) AS photoIds, 
             GROUP_CONCAT(pp.photo) AS photos 
      FROM product_photos pp
      GROUP BY pp.product_id
     ) pp
     ON p.id = pp.product_id LEFT JOIN
     (SELECT i.product_id,
             GROUP_CONCAT(i.size) AS sizes,                                  
             GROUP_CONCAT(i.quantity) as quantitys
      FROM inventory i
      GROUP BY i.product_id
     ) i
     ON p.id = i.product_id 
WHERE p.id = ?;

注意事项:

  • 您需要来自products 表的LEFT JOIN,而不是RIGHT JOIN。据推测,您需要有关产品是否可用的信息,而不仅仅是它是否有库存。
  • 您应该包含一个ORDER BY,这样GROUP_CONCAT() 的值保证顺序相同。也就是说,例如,第一个 id 匹配第一个图像。
  • 表别名使查询更易于编写和阅读。

以上内容应该更有效(并且比使用UNIONUNION ALL 更容易编码和遵循0)。也就是说,“n”行上的两个聚合应该比“2 * n”行上的一个聚合更有效。在更复杂的数据库中,此公式还为优化器提供了更多信息。

因为你只想要一个产品,所以在聚合之前过滤实际上更有效:

SELECT p.*
       pp.photoIds, pp.photos,
       i.sizes, i.quantitys
FROM products p LEFT JOIN
     (SELECT pp.product_id,
             GROUP_CONCAT(pp.id) AS photoIds, 
             GROUP_CONCAT(pp.photo) AS photos 
      FROM product_photos pp
      WHERE pp.product_id = ?
      GROUP BY pp.product_id
     ) pp
     ON p.id = pp.product_id LEFT JOIN
     (SELECT i.product_id,
             GROUP_CONCAT(i.size) AS sizes,                                  
             GROUP_CONCAT(i.quantity) as quantitys
      FROM inventory i
      WHERE i.product_id = ?
      GROUP BY i.product_id
     ) i
     ON p.id = i.product_id 
WHERE p.id = ?;

这种情况下,需要传3次参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-11
    • 2015-02-15
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多