mysql LEFT JOIN仅第一行

eyh26e7m  于 2023-11-16  发布在  Mysql
关注(0)|答案(9)|浏览(139)

我读过很多关于只获取左连接的第一行的线程,但是,出于某种原因,这对我不起作用。
下面是我的结构(当然是简化的)

订阅

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

字符串

艺人

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

feeds_artist

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_artist的第一行,但这已经不起作用了。
我不能使用TOP,因为我的数据库,我不能按feeds_artists.artist_id分组结果,因为我需要按日期排序(我通过这种方式分组得到结果,但结果不是最新的)
尝试了一些与外部应用以及-没有成功,以及。老实说,我真的不能想象发生了什么事,在这些行-可能是最大的原因,我不能让这个工作。
解决方案:

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'

nle07wnf

nle07wnf1#

如果你可以假设艺术家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
  )

字符串

vjrehmav

vjrehmav2#

不带子选择的版本:

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

字符串

zlhcx6iw

zlhcx6iw3#

@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'

字符串

bweufnob

bweufnob4#

根据这里的几个答案,我发现了一些对我有用的东西,我想概括一下,解释一下到底发生了什么。
转换:

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的条件从ON移动到内部查询WHEREMIN(primary key)LIMIT 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的信息

pxy2qtax

pxy2qtax5#

下面是我使用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

字符串

6jjcrrmo

6jjcrrmo6#

我用了其他的东西(我认为更好......),并希望分享它:
我创建了一个具有“group”子句的VIEW

CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code

SELECT * FROM client INNER JOIN vCountries on client_province = province_id

字符串
我想说的是,我认为我们需要做这个解决方案,因为我们在分析中做了一些错误的事情。至少在我的情况下。但有时候这样做比重新设计一切更便宜。
我希望它能帮上忙!

ia2d9nvy

ia2d9nvy7#

我想给给予一个更 * 一般化的答案 *。一个将处理 * 任何情况下,当你想只选择第一个项目在左连接 *。
你可以使用一个子查询,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
这是灵活的,因为这将命令的权力完全掌握在你的手中。但是,经过大量的测试,* 它不会在大量用户和大量数据的情况下很好地扩展。
但是,它在为管理员运行数据密集型报告时很有用。

vcudknz3

vcudknz38#

我知道这不是一个直接的解决方案,但因为我已经面对过这个问题,这对我来说一直是一个巨大的问题,而且使用左连接选择等有时会导致数据库和服务器的沉重进程成本,我更喜欢在php中使用数组来做这种左连接,就像这样:
首先从第二个表中获取范围内的数据,当您只需要第二个表中的一行时,只需保存它们,并将左连接公共列作为结果数组中的键。
SQL 1:

$sql = SELECT artist_id FROM feeds_artists fa WHERE fa.feed_id {...RANGE...}
    $res = $mysqli->query($sql);
if ($res->num_rows > 0) {
    while ($row = $res->fetch_assoc()) {
        $join_data[...$KEY...] = $row['artist_id'];
}

字符串
然后,获取基本数据并从前面的数组中添加左连接表的详细信息,同时像这样获取它们:
SQL 2:

$sql = SELECT * FROM feeds f WHERE f.id {...RANGE...};
$res = $mysqli->query($sql);
if ($res->num_rows > 0) {
    while ($row = $res->fetch_assoc()) {
        $key = $row[in_common_col_value];
        $row['EXTRA_DATA'] = $join_data[$key];
        $final_data[] = $row;
}


现在,您将拥有一个$final_data数组,其中包含来自$join_data数组的所需额外数据。这通常适用于日期范围数据,如下所示。

wb1gzix0

wb1gzix09#

对于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

字符串

相关问题