[英]MySQL JOINS: Select one row from child table is condition is met, otherwise NULL
I am trying to join two tables but I am having some trouble. 我试图加入两个表,但是遇到了一些麻烦。 This is the main table,
packs
这是主表,
packs
And here is the second table, media
这是第二张桌子,
media
The media
is for storing images of packs
. 该
media
用于存储packs
图像。 Each pack can have 0 or more images. 每个包可以包含0个或更多图像。 When the pack has images, one of them will have the
is_default
field set to 1
to indicate the main image to show. 当包中有图像时,其中之一将
is_default
字段设置为1
以指示要显示的主图像。
I want to get all pack and one image for each. 我想获取所有包装和一张图片。 If there are no images, then just a simple
NULL
, otherwise get the image that is is_default
. 如果没有图像,则仅是一个简单的
NULL
,否则获取is_default
的图像。
Here is my query. 这是我的查询。
SELECT
pack.*,
( SELECT media.src FROM packs pack LEFT JOIN packs_media media ON pack.id = media.pack_id WHERE media.is_default = 1 GROUP BY media.id LIMIT 1 ) AS image
FROM packs pack
LEFT JOIN packs_media ON media.pack_id = pack.id
GROUP BY pack.id
ORDER BY pack.id DESC
I have a total of three packs, and only one of them has some images. 我一共有三包,其中只有一包有一些图片。 The query returns 3 results.
该查询返回3个结果。 The problem is that all three results have the same
image
, when only one should and the other two should have the image
field null/empty. 问题是,当只有一个结果应具有相同的
image
时,所有三个结果应具有相同的image
,而其他两个结果的image
字段应为空/空。
Is there any way of doing this with one query only ? 有什么办法只对一个查询执行此操作? I want to avoid querying the
media
table in a loop. 我想避免循环查询
media
表。
Thank you 谢谢
You need a correlated subquery rather than a join: 您需要一个相关的子查询而不是联接:
SELECT p.*,
(SELECT m.src
FROM packs_media m
WHERE p.id = media.p
ORDER BY m.is_default DESC, m.id
LIMIT 1
) AS image
FROM packs p
ORDER BY p.id DESC;
In fact, from the description of the problem, no JOIN
is necessary in the outer query either. 实际上,从问题的描述来看,外部查询中也不需要
JOIN
。 So the GROUP BY
is not needed either. 因此,也不需要
GROUP BY
。
Note the change to the ORDER BY
clause. 注意对
ORDER BY
子句的更改。 This guarantees that the default value is chosen first. 这样可以确保首先选择默认值。
And, your query gets the same value for all rows because the subquery is independent of the outer query. 并且,由于子查询独立于外部查询,因此查询对所有行都具有相同的值。 So, the same value is always chosen.
因此,始终选择相同的值。
I had a similar problem lately, and it has a really-really sweet solution, to be honest. 我最近也遇到过类似的问题,说实话,它确实有一个非常好的解决方案。 At first glance, an obvious try would be adding the
WHERE
condition is_default = 1
. 乍一看,显而易见的尝试是添加
WHERE
条件is_default = 1
。 However, if we do this, where there are no images, the condition won't be met, meaning where it should return NULL
, it just skips that row. 但是,如果执行此操作,则在没有图像的情况下将不满足条件,这意味着它应返回
NULL
,而只是跳过该行。
However, if you add this condition to the LEFT JOIN
part, as I did, it works like a charm. 但是,如果像我一样将此条件添加到“
LEFT JOIN
部分中,它的工作原理就像一种魅力。 It's beacause if the LEFT JOIN
conditions met, it returns the image, and if it doesn't, it returns NULL
, per the definition of LEFT JOIN
. 它东阳如果
LEFT JOIN
条件满足,它返回的形象,如果没有,则返回NULL
,每定义LEFT JOIN
。
So the result should be: 因此结果应为:
SELECT pack.*, media.src
FROM packs pack
LEFT JOIN media
ON media.pack_id = pack.id
AND media.is_default = 1
And I think you shouldn't add GROUP BY it just messes things up. 而且我认为您不应该添加GROUP BY只会使事情搞砸。
If you want to solve your problem even when there's no is_default
... well, that is a harder nut to crack, but I think I have a solution which won't dwell into long lines of conditions and subqueries. 如果即使在没有
is_default
情况下也想解决您的问题,那么,这是一个很难解决的问题,但是我认为我有一个解决方案,不会涉及很多条件和子查询。 Sadly, I have the feeling that this problem can't be solved without a subquery. 可悲的是,我感到没有子查询无法解决此问题。 My idea was not to choose the item whose
media.is_default
equals to 1
, rather which has the highest media.is_default
. 我的想法不是选择
media.is_default
等于1
的项目,而是选择media.is_default
最高的media.is_default
。 As follows: 如下:
SELECT pack.*, media.src
FROM packs pack
LEFT JOIN media
ON media.pack_id = pack.id
AND media.id =
(SELECT m.id FROM media m
WHERE m.pack_id = media.pack_id
ORDER BY m.is_default DESC
LIMIT 1
)
EXPLANATION: This is how it works: we order all by is_default
in a descending order, and refer back to the outer query to use only the current pack_id
(I hope it works this way.) If there is a 1, it obviously will be the first item, otherwise it will be a random item, most likely the first in order of ID. 解释:这是这样工作的:我们按
is_default
所有顺序降序排列,然后返回外部查询以仅使用当前的pack_id
(我希望它以这种方式工作。)如果有1,则显然是第一个项目,否则将是一个随机项目,最有可能是ID的第一个项目。 And you just take that element and use it. 您只需使用该元素并使用它。 I cannot guarantee if it works at all.
我不能保证它是否完全有效。 Try using
IN
instead of =
as a possible bug fix. 尝试使用
IN
代替=
作为可能的错误修复。
However, I would NOT advise this solution. 但是,我不建议这种解决方案。 I'd rather change the previous logic to avoid this problem (eg when the user adds a media to an empty pack,
is_default = 1
on that picture). 我宁愿更改以前的逻辑来避免此问题(例如,当用户将媒体添加到空包时,该图片上的
is_default = 1
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.