LEFT JOIN仅第一行

Kdd*_*ddC 125 mysql join left-join groupwise-maximum

我读了许多关于只获得左连接的第一行的线程,但是,由于某种原因,这对我不起作用.

这是我的结构(当然简化)

饲料

id |  title | content
----------------------
1  | Feed 1 | ...
Run Code Online (Sandbox Code Playgroud)

艺术家

artist_id | artist_name
-----------------------
1         | Artist 1
2         | Artist 2
Run Code Online (Sandbox Code Playgroud)

feeds_artists

rel_id | artist_id | feed_id
----------------------------
1      |     1     |    1 
2      |     2     |    1 
...
Run Code Online (Sandbox Code Playgroud)

现在我想获得文章并加入第一位艺术家,我想到了这样的事情:

SELECT *
    FROM feeds 
    LEFT JOIN feeds_artists ON wp_feeds.id = (
        SELECT feeds_artists.feed_id FROM feeds_artists
        WHERE feeds_artists.feed_id = feeds.id 
    LIMIT 1
    )
WHERE feeds.id = '13815'
Run Code Online (Sandbox Code Playgroud)

只是为了获得feed_artists的第一行,但这已经不起作用了.

我无法使用TOP因为我的数据库而且我无法对结果进行分组,feeds_artists.artist_id因为我需要按日期对它们进行排序(我通过这种方式对结果进行分组,但结果不是最新的)

用OUTER APPLY尝试了一些东西 - 也没有成功.说实话,我无法想象这些行中会发生什么 - 可能是我无法让这个工作的最大原因.

解:

SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
    SELECT artist_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.id
    LIMIT 1
)
WHERE f.id = '13815'
Run Code Online (Sandbox Code Playgroud)

Mat*_*dge 91

如果您可以假设艺术家ID随着时间的推移而递增,那么这MIN(artist_id)将是最早的.

所以尝试这样的事情(未经测试......)

SELECT *
  FROM feeds f
  LEFT JOIN artists a ON a.artist_id = (
    SELECT
      MIN(fa.artist_id) a_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.feed_id
  ) a
Run Code Online (Sandbox Code Playgroud)

  • 此时不会简单的子查询更好吗?因为现在你有一个连接和一个子查询.只是问因为我正在寻找同样问题的解决方案:) (3认同)
  • 子查询太慢。 (3认同)
  • @Sinux 定义“太慢”。这取决于记录数量和给定的要求。 (2认同)
  • 这不行!子查询不允许传递父查询中的字段! (2认同)

小智 51

没有子选择的版本:

   SELECT f.title,
          f.content,
          MIN(a.artist_name) artist_name
     FROM feeds f
LEFT JOIN feeds_artists fa ON fa.feed_id = f.id
LEFT JOIN artists a ON fa.artist_id = a.artist_id
 GROUP BY f.id
Run Code Online (Sandbox Code Playgroud)

  • 这个查询是错误的.它将选择"最低"的艺术家名称而不是第一批艺术家的名字. (24认同)
  • 这个问题错了......但正是我想要的.在我的情况下,我只想要我加入的表中的第一个ID. (5认同)
  • 我不认为这将是第一行(第一个id或第一个别的东西),它只是随机选择左连接行中的一个. (2认同)
  • 这里的问题是,如果你决定做一个 COUNT 或 SUM,你就会搞砸数据。Subselect 的问题在于它在创建临时表时获取数据更重......我希望 MySql 可以在 LEFT JOIN 级别上有一个 LIMIT 。 (2认同)

Kdd*_*ddC 16

@Matt Dodges的回答使我走上了正确的轨道。再次感谢您提供所有答案,在此期间,这对很多人都有所帮助。像这样工作:

SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
    SELECT artist_id
    FROM feeds_artists fa 
    WHERE fa.feed_id = f.id
    LIMIT 1
)
WHERE f.id = '13815'
Run Code Online (Sandbox Code Playgroud)

  • 这是仅适用于第一行的答案。当没有 `f.id` 条件时中断。 (5认同)

ori*_*dam 5

基于这里的几个答案,我发现了一些对我有用的东西,我想概括和解释发生了什么。

转变:

LEFT JOIN table2 t2 ON (t2.thing = t1.thing)
Run Code Online (Sandbox Code Playgroud)

到:

LEFT JOIN table2 t2 ON (t2.p_key = (SELECT MIN(t2_.p_key) 
    FROM table2 t2_ WHERE (t2_.thing = t1.thing) LIMIT 1))
Run Code Online (Sandbox Code Playgroud)

连接 t1 和 t2 的条件从ON和移动到内部查询中WHERE。在MIN(primary key)LIMIT 1确保只有1行由内部查询返回。

选择一个特定的行后,我们需要告诉ON它是哪一行。这就是为什么ON要比较连接表的主键。

您可以使用内部查询(即订单+限制),但它必须返回所需行的一个主键,该主键将告诉ON要加入的确切行。

更新 - 适用于 MySQL 5.7+

另一个与 MySQL 5.7+ 相关的选项是使用ANY_VALUE+ GROUP BY。它将选择一个不一定是第一个的艺术家姓名。

SELECT feeds.*,ANY_VALUE(feeds_artists.name) artist_name
    FROM feeds 
    LEFT JOIN feeds_artists ON feeds.id = feeds_artists.feed_id 
GROUP BY feeds.id
Run Code Online (Sandbox Code Playgroud)

关于 ANY_VALUE 的更多信息:https ://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html