【问题标题】:MySQL INNER JOIN to find the max value of group of rowsMySQL INNER JOIN 查找行组的最大值
【发布时间】:2012-12-29 19:37:50
【问题描述】:

我已经在这里展示了我正在尝试做的事情的示例

http://sqlfiddle.com/#!2/514d2/2

此演示查找“bids”表中不是每个listing_id 最高出价的所有行。我需要做的是找到所有列表,其中 $userid(在本例中为用户 1)是最高出价者。

有人可以帮我解决这个问题吗?

对于那些不使用 SQLFiddle 的人...

  • 表名:列表
  • 表名:出价

SQL:

SELECT listings.end_date, 
    listings.user_id, 
    listings.title, 
    listings.auc_fp, 
    listings.id, 
    listings.auc_image1 
FROM listings 
INNER JOIN 
    (SELECT 
     listing_id, 
     user_id, 
     bid maxBid 
 FROM bids 
 WHERE bid 
 NOT IN 
     (SELECT MAX(bid) 
      FROM bids) 
      GROUP BY 
         listing_id, 
         user_id) 
    bids ON 
      listings.id = bids.listing_id 
  WHERE bids.user_id=1 
  AND listings.end_date > NOW() 
  ORDER BY listings.list_ts DESC

此查询成功找到 $userid 已出价但不是最高出价者的所有列表。我想查找 $userid 已出价且出价最高者的所有列表。

【问题讨论】:

  • 请在问题中包含足够的信息,以便我们无需使用 SQL Fiddle 或其他方式即可回答。您还需要提供 SSCCE (Short, Self-Contained, Correct Example)。在示例 Listings 表中有 17 列;其中至少有 11 个对您的问题不重要。在没有真正帮助问题的情况下,它们会使理解您尝试做什么的过程复杂化。
  • 我已经编辑了上面的问题,我也会编辑 SQLFiddle。谢谢。
  • 感谢您更新问题。你不需要用 IN 替换 NOT IN 来获得你想要的结果吗?
  • 嗯,这就是我的想法,但它不起作用。我想也许我错过了什么。当我这样做时,它根本不会返回任何结果。
  • SQL 的布局很奇怪;有一个我不希望有的右括号,所以我误读了查询结构。

标签: mysql inner-join max


【解决方案1】:

初步观察

原始查询可以重新格式化,以便于阅读,如下所示:

SELECT listings.end_date, 
       listings.user_id, 
       listings.title, 
       listings.auc_fp, 
       listings.id, 
       listings.auc_image1 
  FROM listings 
  JOIN (SELECT listing_id, 
               user_id, 
               bid maxBid 
          FROM bids 
         WHERE bid NOT IN (SELECT MAX(bid) FROM bids) 
         GROUP BY listing_id, user_id
       ) AS bids
    ON listings.id = bids.listing_id 
 WHERE bids.user_id = 1 
   AND listings.end_date > NOW() 
 ORDER BY listings.list_ts DESC

我注意到别名为maxBid 的列不一定是任何列表的最高出价。此查询也仅适用于仍处于打开状态的列表。我不相信它会产生预期的答案。唯一排除的出价是包含任何列表的总体最高出价的出价。


TDQD — 测试驱动的查询设计

真正的问题是:

查找 $userid (= 1) 出价且最高出价者的所有当前打开的列表。

是时候做 TDQD 了——测试驱动的查询设计;我的大脑工作速度不够快,无法一次完成所有操作。

每个列表的最高出价

SELECT listing_id, MAX(bid) AS maxBid
  FROM bids
 GROUP BY listing_id

查找出价最高的用户是用户 1 的商家信息的出价

SELECT b.listing_id
  FROM bids AS b
  JOIN (SELECT listing_id, MAX(bid) AS maxBid
          FROM bids
         GROUP BY listing_id
       ) AS m
    ON m.listing_id = b.listing_id AND m.maxBid = b.bid
 WHERE b.user_id = 1

查找出价最高的用户是用户 1 的列表

SELECT l.*
  FROM listings AS l
  JOIN (SELECT b.listing_id
          FROM bids AS b
          JOIN (SELECT listing_id, MAX(bid) AS maxBid
                  FROM bids
                 GROUP BY listing_id
               ) AS m
            ON m.listing_id = b.listing_id AND m.maxBid = b.bid
         WHERE b.user_id = 1
       ) AS u
    ON l.id = u.listing_id

限制查询打开列表

SELECT l.*
  FROM listings AS l
  JOIN (SELECT b.listing_id
          FROM bids AS b
          JOIN (SELECT listing_id, MAX(bid) AS maxBid
                  FROM bids
                 GROUP BY listing_id
               ) AS m
            ON m.listing_id = b.listing_id AND m.maxBid = b.bid
         WHERE b.user_id = 1
       ) AS u
    ON l.id = u.listing_id
 WHERE l.end_date > NOW()

您可以并且应该将* 替换为您感兴趣的确切列。如果您需要出价详细信息,也可以获取这些信息。


针对 Informix 进行测试

需要进行细微的语法更改——NOW() 被 CURRENT YEAR TO SECOND 替换——但这只会影响最后一个查询。在 DDL 上需要做更多的工作才能将语法转换为更接近 DBMS 中立的格式。 MySQL 有一些奇怪的约定。

未来读者请注意:将NOW()CURRENT YEAR TO SECOND 替换为2012-12-29 12:37:43 等值以获得相同的结果。数据中的列表从 `2013-01-10 00:00:001 开始过期。

查询 1:

SELECT listing_id, MAX(bid) AS maxBid
  FROM bids
 GROUP BY listing_id;

输出 1:

listing_id  maxbid
34          95.37
40          103.00
38          507.00
41          94.00
48          76.00
6469        22.00
6472        5.00
37          511.00
31          100.00

查询 2:

SELECT b.listing_id
  FROM bids AS b
  JOIN (SELECT listing_id, MAX(bid) AS maxBid
          FROM bids
         GROUP BY listing_id
       ) AS m
    ON m.listing_id = b.listing_id AND m.maxBid = b.bid
 WHERE b.user_id = 1;

输出 2:

listing_id
34
37
48
6469
6472

查询 3:

SELECT l.end_date, l.user_id, l.title, l.id
  FROM listings AS l
  JOIN (SELECT b.listing_id
          FROM bids AS b
          JOIN (SELECT listing_id, MAX(bid) AS maxBid
                  FROM bids
                 GROUP BY listing_id
               ) AS m
            ON m.listing_id = b.listing_id AND m.maxBid = b.bid
         WHERE b.user_id = 1
       ) AS u
    ON l.id = u.listing_id;

输出 3: end_date user_id 标题 ID 2013-01-09 08:11:16 1 圣诞树 6469 2013-01-11 09:17:31 3 另一个测试项目6472

查询 4

SELECT l.end_date, l.user_id, l.title, l.id
  FROM listings AS l
  JOIN (SELECT b.listing_id
          FROM bids AS b
          JOIN (SELECT listing_id, MAX(bid) AS maxBid
                  FROM bids
                 GROUP BY listing_id
               ) AS m
            ON m.listing_id = b.listing_id AND m.maxBid = b.bid
         WHERE b.user_id = 1
       ) AS u
    ON l.id = u.listing_id
 WHERE l.end_date > CURRENT YEAR TO SECOND;

输出 4:

end_date                user_id     title                   id
2013-01-09 08:11:16     1           Christmas Tree          6469
2013-01-11 09:17:31     3           Another test item       6472

【讨论】:

    【解决方案2】:

    这应该可以满足您使用左连接的需要,以确保每个产品都没有更好的出价;

    SELECT DISTINCT listings.end_date, listings.user_id, listings.title, 
           listings.auc_fp, listings.id, listings.auc_image1
    FROM listings 
    JOIN bids b1 
      ON b1.listing_id=listings.id 
    LEFT JOIN bids b2 
      ON b2.listing_id=listings.id AND b1.bid < b2.bid
    WHERE b1.user_id = 1
      AND b2.bid IS NULL
      AND listings.end_date > NOW()
    

    An SQLfiddle based on the original to test with.

    【讨论】:

    • 非常感谢!我一直使用 INNER JOIN 得到错误的结果,但我以前从未使用过 LEFT JOIN。您能告诉我如何更改此查询以查找用户出价但不是高出价者的所有列表吗?我有一个正在使用的查询,但它也返回了错误的结果。
    • @Budove 对不起,现在没有太多时间来写一些特别优雅的东西,但是试试this SQLfiddle。请注意,用户 ID 需要在查询中设置两次才能工作:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    相关资源
    最近更新 更多