联接两个表,按第二个表上的字段排序,没有重复项

时间:2019-11-16 12:18:23

标签: mysql

我很抱歉,但是我无法理解这一点(即使在搜索并尝试了一些方法之后也是如此)。我要做的就是联接两个表,然后对article_translations表中created_at降序的联接进行排序。但是,我需要唯一的条目。

我有两个表:

articles
--------
id
user_id
article_translations
--------
id
article_id (brings this table together with the other one)
locale
title
...
created_at
updated_at

执行mysql查询:

SELECT * from articles
JOIN article_translations as t on t.article_id = articles.id 
ORDER BY t.created_at desc

我获得了带有相应相关条目的联接表。

articles.id t.article_id created_at
1               1           ''
1               1           ''
2               2           ''

当我尝试不删除重复项时,在本例中id为1的文章中,我得到了一个讨厌的错误:

SELECT列表的表达式#3不在GROUP BY子句中,并且包含未聚合的列'blog.t.id',该列在功能上不依赖于GROUP BY子句中的列;这与sql_mode = only_full_group_by

不兼容

所需的结果将是:

articles.id t.article_id created_at
1               1           ''
2               2           ''

请帮忙...谢谢!

4 个答案:

答案 0 :(得分:2)

获取唯一行的唯一方法是,您是否希望每个id的最新(或最早?)日期,如果您group by a.id, t.article_id并进行汇总,则可以这样做:

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 

如果要使用2个表的所有列,请首先使用article_translationsNOT EXISTS获取唯一行,然后加入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

如果article_translationscreated_at的行数最多为article_id,而行数不超过1,则此方法有效。

对于MySql 8.0+,您可以使用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

答案 1 :(得分:0)

因为您确实希望所有列:

如果您尝试仅保留具有最新创建日期的文章翻译,那么假设创建日期对于给定文章的翻译而言是唯一的,一种方法是创建一个子查询,为每个article_translation.article_id计算article_translation.created_at列的最大值:

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

如果创建日期不是唯一的,或者即使不是,那么这也应该起作用:

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

答案 2 :(得分:0)

您几乎可以回答问题中的查询。您只需要添加“ distinct”关键字:

SELECT distinct * from articles
JOIN article_translations as t on t.article_id = articles.id 
ORDER BY t.created_at desc`

答案 3 :(得分:0)

感谢forpas提供正确的答案。我基本上需要结合Laravel Eloquent模型和急切加载的查询。万一有人在乎,那就是现在的最终解决方案:

$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();

纯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