Reputation: 121
My apologies but I cannot get my head around this one (even not after searching and trying out a few things). All I want to do is join two tables and then sort the join descending on the created_at in the article_translations table. However, I need unique entries.
I have two tables:
articles
--------
id
user_id
article_translations
--------
id
article_id (brings this table together with the other one)
locale
title
...
created_at
updated_at
Performing mysql query:
SELECT * from articles
JOIN article_translations as t on t.article_id = articles.id
ORDER BY t.created_at desc
I get the joined tables with the corresponding related entries.
articles.id t.article_id created_at
1 1 ''
1 1 ''
2 2 ''
When I try no to get rid of the duplicates, in this case of the article with id = 1, I get a nasty error:
Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'blog.t.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
The Desired result would be:
articles.id t.article_id created_at
1 1 ''
2 2 ''
Any help please... Thank You!
Upvotes: 2
Views: 5212
Reputation: 44043
Since you do want all the columns:
If you are trying to keep just the article translation with the latest creation date, then assuming the creation dates are unique for a give article's translations, one way would be to create a subquery that computes for each article_translation.article_id
the maximum article_translation.created_at
column value:
SELECT articles.*, t.* from articles
JOIN article_translations as t on t.article_id = articles.id
JOIN (
SELECT article_id, max(created_at) as created_at from article_translations
GROUP BY article_id
) a_t on t.article_id = a_t.article_id and t.created_at = a_t.created_at
ORDER BY t.created_at desc
If the creation dates are not unique, or even if they are, then this should also work:
SELECT articles.*, t.* from articles
JOIN article_translations as t on t.article_id = articles.id
AND t.article_id = (
SELECT t2.article_id from article_translations t2
WHERE t2.article_id = t.article_id
ORDER BY created_date DESC
LIMIT 1
)
ORDER BY t.created_at DESC
Upvotes: 0
Reputation: 121
Thanks forpas for providing the correct answer. I needed this query basically for a Laravel Eloquent model in combination with eager loading. In case anybody cares, that's how the final solution now looks like:
$articles = Article::join('article_translations as at', function ($join) {
$join->on('articles.id', '=', 'at.article_id');
})
->select('articles.id',
'articles.user_id',DB::raw('MAX(at.created_at) as created_at'))
->groupBy('at.article_id')
->orderBy('created_at', 'desc')
->with('translations')
->get();
Pure SQL
SELECT at.article_id, MAX(at.created_at) as created_at FROM articles as a
INNER JOIN article_translations as at
ON a.id = at.article_id
GROUP BY at.article_id
ORDER BY MAX(created_at) desc
Upvotes: 0
Reputation: 339
You are almost there with the query in the question. You just need to add the distinct keyword:
SELECT distinct * from articles
JOIN article_translations as t on t.article_id = articles.id
ORDER BY t.created_at desc`
Upvotes: 0
Reputation: 164069
The only way to get unique rows is if you want the latest (or the earliest?) date for each id
, which you can do if you group by a.id, t.article_id
and aggregate:
SELECT a.id, t.article_id, MAX(t.created_at) AS created_at
FROM articles AS a INNER JOIN article_translations AS t
ON t.article_id = a.id
GROUP BY a.id, t.article_id
ORDER BY MAX(t.created_at) DESC
If you want all the columns of the 2 tables, first get unique rows from article_translations
with NOT EXISTS
and then join to articles
:
SELECT *
FROM articles AS a INNER JOIN (
SELECT t.*
FROM article_translations t
WHERE NOT EXISTS (
SELECT 1 FROM article_translations
WHERE article_id = t.article_id AND created_at > t.created_at
)
) AS t
ON t.article_id = a.id
ORDER BY t.created_at DESC
This will work if there are not more than 1 rows in article_translations
with the same maximum created_at
for an article_id
.
For MySql 8.0+ you could use ROW_NUMBER()
:
SELECT t.* FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY t.created_at DESC) rn
FROM articles AS a INNER JOIN article_translations AS t
ON t.article_id = a.id
) AS t
WHERE t.rn = 1
Upvotes: 2