【问题标题】:Limit results from joined table to one row将连接表的结果限制为一行
【发布时间】:2010-06-05 01:19:29
【问题描述】:

这是一个简化的表结构:

TABLE products (
 product_id INT (primary key, auto_increment),
 category_id INT,
 product_title VARCHAR,
 etc
);

TABLE product_photos (
 product_photo_id (primary key, auto_increment),
 product_id INT,
 photo_href VARCHAR,
 photo_order INT
);

一个产品可以有多张照片,每个产品的第一张产品照片(基于 photo_order)是默认照片。

现在,我只需要产品详细信息页面上的所有照片,但在我列出多个产品的页面上,例如产品目录页面,我只想显示默认照片。

所以我想做的是查询产品列表,包括每个产品的默认照片。

这显然不起作用,它将返回所有照片,其中每张照片的产品信息都重复:

SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph
ON p.product_id=ph.product_id
ORDER BY p.product_title ASC

我需要弄清楚如何做这样的事情,但我不知道语法(或者是否可能)

SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph
    ON p.product_id=ph.product_id  **ORDER BY ph.photo_order ASC LIMIT 1**
ORDER BY p.product_title ASC

编辑:我在以下答案的帮助下找到了解决方案,谢谢大家!

SELECT p.*, ph.*
FROM products AS p
LEFT JOIN product_photos AS ph 
    ON p.product_id=ph.product_id
    AND ph.photo_order =
    (
        SELECT MIN(z.photo_order)
        FROM product_photos AS z
        WHERE z.product_id=p.product_id
    )
GROUP BY p.product_id
ORDER BY p.product_title ASC

【问题讨论】:

  • 请提供 PRODUCT_PHOTOS 的示例 - 我想看看 PHOTO_ORDER 如何控制默认值,因为您没有提供数据类型
  • photo_order 只是一个整数,应该每个产品都是唯一的,但不一定保证
  • 如果您切换到正确的连接并通过以下方式订购:.product_title ASC、.photo_order ASC 我认为您将获得每个产品的一行,这将是第一张照片。您不会看到没有照片的产品(这可能是个问题)。不过,它应该是一个更简单的查询。
  • 是的,这会是个问题,因为不能保证所有产品都至少有一张照片(很可能很多都没有)

标签: sql mysql


【解决方案1】:
SELECT p.*, ph.*
FROM products AS p
INNER JOIN product_photos AS ph
    ON p.product_id = ph.product_id
LEFT JOIN product_photos AS ph2
    ON p.product_id = ph2.product_id
    AND ph2.photo_order < ph.photo_order
WHERE ph2.photo_order IS NULL
ORDER BY p.product_title ASC

注意它两次加入 product_photos 表的方式。 WHERE ph2.photo_order IS NULL 将丢弃除最低照片顺序之外的所有照片。但它不会保护您免受重复的 product_id / photo_orders 组合的影响,如果是这种情况,您可以在 p.id 上添加 GROUP BY

【讨论】:

  • 干得好。没有子查询/派生表。只需要 product_id 和 photo_order 的索引。
【解决方案2】:

用途:

SELECT p.*,
       pp.*
  FROM PRODUCTS p
  JOIN PRODUCT_PHOTOS pp ON pp.product_id = p.product_id
  JOIN (SELECT x.product_id,
               MIN(x.photo_order) AS default_photo
          FROM PRODUCT_PHOTOS x
      GROUP BY x.product_id) y ON y.product_id = pp.product_id
                              AND y.default_photo  = pp.photo_order

【讨论】:

  • 我不知道这是否符合他的要求。他特别指出要使用 photo_order 字段,而不是 product_photo_id 字段。
  • 它完全符合需要,我只是尽量避免子查询,因此是另一个答案。
  • @Wrikken:与派生表/内联视图的联接不是子查询。对我来说,至少……
  • 同意派生表。你改变了你的anwser还是我完全误读了它?如果我错了,我深表歉意。
  • 哦哦,不说了。不完全是火焰战争诱饵,但是派生表是否是子查询是非常有争议的,我现在不会开始。这不是批评,我对子查询和/或派生表的不使用有时是不合逻辑的。
【解决方案3】:
    SELECT p.*, ph.*
    FROM products AS p
    LEFT JOIN product_photos AS ph ON p.product_id=ph.product_id
    ORDER BY p.product_title ASC, ph.photo_order ASC
    GROUP BY p.product_id
    LIMIT 0,10

【讨论】:

    【解决方案4】:
    SELECT ...
      ....
    GROUP BY p.product_id
    

    【讨论】:

    • 感谢您的回复,尽管此解决方案不会尊重 photo_order 列。
    • 尝试颠倒排序顺序。
    猜你喜欢
    • 2012-07-08
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 2012-12-13
    • 1970-01-01
    相关资源
    最近更新 更多