175

我读了很多关于只获取左连接的第一行的帖子,但是,由于某种原因,这对我不起作用。

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

饲料

id |  title | content
----------------------
1  | Feed 1 | ...

艺术家

artist_id | artist_name
-----------------------
1         | Artist 1
2         | Artist 2

feeds_artists

rel_id | artist_id | feed_id
----------------------------
1      |     1     |    1 
2      |     2     |    1 
...

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

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'

只是为了获得 feeds_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'
4

8 回答 8

120

如果您可以假设艺术家 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
于 2013-03-25T23:10:07.093 回答
57

没有子选择的版本:

   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
于 2013-12-12T11:47:24.850 回答
41

@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'
于 2019-01-17T09:59:54.453 回答
7

基于这里的几个答案,我发现了一些对我有用的东西,我想概括并解释正在发生的事情。

兑换:

LEFT JOIN table2 t2 ON (t2.thing = t1.thing)

至:

LEFT JOIN table2 t2 ON (t2.p_key = (SELECT MIN(t2_.p_key) 
    FROM table2 t2_ WHERE (t2_.thing = t1.thing) LIMIT 1))

连接 t1 和 t2 的条件从ONand 移到内部查询WHERE中。MIN(primary key)orLIMIT 1确保内部查询只返回 1 行。

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

您可以使用内部查询(即 order+limit),但它必须返回所需行的一个主键,该主键将告诉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

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

于 2020-04-30T11:24:38.997 回答
2

我用过别的东西(我觉得更好......)并想分享它:

我创建了一个具有“组”子句的 VIEW

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

我想说的是,我认为我们需要做这个解决方案,因为我们在分析中做错了什么......至少在我的情况下......但有时这样做更便宜重新设计一切......

我希望它有帮助!

于 2018-03-09T14:11:45.437 回答
1

我想给出一个更笼统的答案当您只想选择 LEFT JOIN 中的第一项时,可以处理任何情况。

您可以使用 GROUP_CONCATS 的子查询(也已排序!),然后只需拆分 GROUP_CONCAT 的结果并仅获取其第一项,就像这样...

LEFT JOIN Person ON Person.id = (
    SELECT SUBSTRING_INDEX(
        GROUP_CONCAT(FirstName ORDER BY FirstName DESC SEPARATOR "_" ), '_', 1)
    ) FROM Person
);

由于我们将DESC作为我们的ORDER BY选项,因此这将为像“Zack”这样的人返回一个 Person id。如果我们想要一个名字像“Andy”的人,我们会将ORDER BY FirstName DESC更改为ORDER BY FirstName ASC

这是灵活的,因为这将订购的权力完全掌握在您的手中。但是,经过大量测试,它在用户和数据量很大的情况下无法很好地扩展。

但是,它在为管理员运行数据密集型报告时很有用。

于 2018-09-17T20:06:11.570 回答
0

这是我使用 group by 子句的答案。

SELECT *
FROM feeds f
LEFT JOIN 
(
    SELECT artist_id, feed_id
    FROM feeds_artists
    GROUP BY artist_id, feed_id 
) fa ON fa.feed_id = f.id
LEFT JOIN artists a ON a.artist_id = fa.artist_id
于 2020-11-24T10:52:51.183 回答
0

对于像 DB2 和 PostgreSQL 这样的数据库,您必须使用关键字LATERAL来指定子查询LEFT JOIN:(这里是针对 DB2)

SELECT f.*, a.*
FROM feeds f
LEFT JOIN LATERAL  
(
    SELECT artist_id, feed_id
    FROM feeds_artists sfa
    WHERE sfa.feed_id = f.id
    fetch first 1 rows only
) fa ON fa.feed_id = f.id
LEFT JOIN artists a ON a.artist_id = fa.artist_id
于 2020-11-25T17:11:55.650 回答