英文:
Filtering by count and specific value from a related table
问题
让我们假设我们有一个名为'grouper'的表格
id | column_a |
---|---|
1 | value |
2 | value |
还有一个名为'translation'的表格,包含以下列
id | locale | text | grouper_id |
---|---|---|---|
1 | en | some en text | 1 |
2 | es | some es text | 1 |
3 | fr | some fr text | 1 |
4 | en | some en text | 2 |
正如我们所看到的,'grouper'与'translation'存在一对多的关系。
我想要查询只有一个相关翻译且该翻译的语言环境是'en'的那些grouper(即,grouper的id是'2',因为它只有一个相关翻译,id是'4',并且这个翻译的语言环境是'en')。
我尝试做如下操作:
SELECT grouper.id,
grouper.column_a
FROM grouper
INNER JOIN translation
ON grouper.id = translation.grouper_id
GROUP BY grouper.id
HAVING COUNT(translation.id) = 1
返回的数据是正确的,但在这种情况下,没有考虑到语言环境。问题是,我不知道如何正确添加'locale'条件。
如果我将它添加为 WHERE translation.locale = 'en'
,结果将是不正确的,因为我将获取所有具有'en'语言环境的translations的grouper,而不管grouper有多少相关翻译。
如果我将条件添加到HAVING子句中,像这样 HAVING COUNT(translation.id) = 1 AND translation.locale = 'en'
,MySQL会抛出错误:
在'having clause'中未知列'translation.locale'。
非常感谢任何帮助。
英文:
Let's say we have a table called 'grouper'
id | column_a |
---|---|
1 | value |
2 | value |
And a table called 'translation' that contains following columns
id | locale | text | grouper_id |
---|---|---|---|
1 | en | some en text | 1 |
2 | es | some es text | 1 |
3 | fr | some fr text | 1 |
4 | en | some en text | 2 |
As we can see 'grouper' has one-to-many relation with 'translation'
What I want is to query only for those groupers that have only one related translation and that translation has to have 'en' locale. (i.e. grouper with id '2' because it has only one related translation with id '4' and this translation has 'en' locale).
I'm trying to do something like this:
SELECT gruper.id,
grouper.column_a
FROM grouper
INNER JOIN translation
ON grouper.id = translation.grouper_id
GROUP BY grouper.id
HAVING COUNT(translation.id) = 1
And returned data is correct but locale is not considered in this case. The thing is, I don't know how to add the 'locale' condition correctly.
If I add it as WHERE translation.locale = 'en'
the result will be incorrect since I will get all groupers with 'en' locale present in translations no matter how many related translations the grouper has.
And if I add the condition to HAVING clause like that HAVING COUNT(translation.id) = 1 AND translation.locale = 'en'
MySQL throws an error:
>Unknown column 'translation.locale' in 'having clause'.
Any help is much appreciated.
答案1
得分: 1
在你的查询中存在两个问题:
- "grouper.column_a" 既没有被聚合,也没有在
GROUP BY
子句中找到。最好将其移到GROUP BY
子句内,以避免细微的错误。 - "translation.locale" 在
HAVING
子句中没有被识别为字段,这是因为这个子句只在聚合已经完成后才被激活,因此 translation 不再存在。为了解决这个问题,你需要对相同的字段进行聚合,或者将其添加到GROUP BY
子句中。前一种解决方案更好,因为第二种会导致不正确的结果(并且也没有意义)。
SELECT grouper.id,
grouper.column_a
FROM grouper
INNER JOIN translation
ON grouper.id = translation.grouper_id
GROUP BY grouper.id, grouper.column_a
HAVING COUNT(translation.id) = 1 AND MAX(translation.locale) = 'en'
如果你知道每个翻译在你的分区内不会重复,就像你分享的示例数据一样,你甚至可以通过检查翻译.locale = en 的总和是否为 1 来将条件减少到一个条件,如下所示:
HAVING SUM(CASE WHEN translation.locale = 'en' THEN 1 ELSE -1 END) = 1
这将确保当这个总和为 1 时,唯一的情况是翻译.locale = 'en',并且没有其他翻译(计数行 = 1)。
输出:
id | column_a |
---|---|
2 | value |
在此查看演示链接。
进一步的参考资料:
英文:
There are two issues in your query:
- "grouper.column_a" is neither aggregated, nor found within the
GROUP BY
clause. It's better to move it inside theGROUP BY
clause to avoid subtle mistakes. - "translation.locale" is not recognized as a field inside the
HAVING
clause, that's because this clause is activated only after the aggregation has already been carried out, for this reason translation doesn't exist anymore. In order to solve this issue, you either need to aggregate the same field, or add it to theGROUP BY
clause. The former solution is preferred, as the second one would lead to incorrect result (and would not make sense as well).
SELECT grouper.id,
grouper.column_a
FROM grouper
INNER JOIN translation
ON grouper.id = translation.grouper_id
GROUP BY grouper.id, grouper.column_a
HAVING COUNT(translation.id) = 1 AND MAX(translation.locale) = 'en'
If you know that each translation cannot be repeated within your partitions, as it seems from your shared sample data, you could even reduce conditions to one only, by checking when sum of translation.locale = en is 1 as follows:
HAVING SUM(CASE WHEN translation.locale = 'en' THEN 1 ELSE -1 END) = 1
This would ensure that the only case when this sum gets 1 is when there's one translation.locale = 'en' and no other translations (count rows = 1).
Output:
id | column_a |
---|---|
2 | value |
Check the demo here.
Further references:
答案2
得分: 1
你可以这样表达:我想要那些最小和最大语言环境都是'en'的分组ID。
你可以使用连接(join)或IN
或EXISTS
子句来实现这个目标。我使用IN
是因为它简单,并且我们只想从分组表中选择数据:
SELECT *
FROM grouper
WHERE id IN
(
SELECT grouper_id
FROM translation
GROUP BY grouper_id
HAVING MIN(locale) = 'en' AND MAX(locale) = 'en'
);
英文:
You can phrase it like this: I want those grouper IDs for which both the minimum and the maximum locale is 'en'.
You can do this with a join or with an IN
or EXISTS
clause. I am using IN
for its simplicity and because we only want to select data from the grouper table:
SELECT *
FROM grouper
WHERE id IN
(
SELECT grouper_id
FROM translation
GROUP BY grouper_id
HAVING MIN(locale) = 'en' AND MAX(locale) = 'en'
);
答案3
得分: 0
你可以使用 inner join
来连接仅有一个翻译(应为 en)的一组组别。
select g.*
from grouper g
inner join (
select grouper_id
from translation
group by grouper_id
having count(*) = 1 and sum(locale='en') = 1
) as s on s.grouper_id = g.id
英文:
You can use inner join
to join a list of groupers that only have one translation, which should be en.
select g.*
from grouper g
inner join (
select grouper_id
from translation
group by grouper_id
having count(*) = 1 and sum(locale='en') = 1
) as s on s.grouper_id = g.id
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论