MySQL - 如何在顺序和分组后 select 不同的行?
MySQL - How to select distinct rows after order and group?
我有一个 table 这样的:
post | date | tags
--------+-----------+-------
post3 | 2016 | bbb
post1 | 2018 | aaa
post2 | 2017 | ccc
post1 | 2018 | bbb
post3 | 2016 | aaa
post2 | 2017 | bbb
post2 | 2017 | bbb
post1 | 2018 | ccc
post3 | 2016 | ccc
我想得到以下结果:
post | date | tags
------- +---------- +--------
post1 | 2018 | aaa
post2 | 2017 | bbb
post3 | 2016 | ccc
换句话说,我想要做的是:首先,根据列(在本例中是日期列)对 table 进行排序。其次,根据另一列(在本例中为列标签)进行分组。最后,我希望 post 列的结果不会重复。
第一部分和第二部分我知道怎么做。我应用下面的查询...
SELECT post, `date`, tag
FROM tabela AS t1
WHERE t1.`date` = (
SELECT MAX(t2.`date`)
FROM tabela AS t2
WHERE t1.tag = t2.tag
)
...我得到以下结果:
post | data | tags
------- +---------- +--------
post1 | 2018 | aaa
post1 | 2018 | bbb
post1 | 2018 | ccc
如您所见,问题是 post1 对所有标签重复。我不希望这种情况发生。我希望根据日期列给出的最高值智能地填充所有行,但不在 post 列中重复。
我该怎么做?
PS: 抱歉英文错误,我不是美国人。
在 v8x 之前的 MySQL 版本中,您可以像这样使用变量:
SELECT
post, `date`, tags
FROM (
SELECT
@row_num :=IF(@prev_value=t.tags, @row_num + 1, 1) AS RowNumber
, t.post
, t.`date`
, t.tags
, @prev_value := t.tags
FROM mytable t
CROSS JOIN (SELECT @row_num :=1, @prev_value :='') vars
ORDER BY
t.tags
, t.`date` DESC
) d
WHERE RowNumber = 1
ORDER BY
tags, `date`
;
+----+-------+------+------+
| | post | date | tags |
+----+-------+------+------+
| 1 | post1 | 2018 | aaa |
| 2 | post1 | 2018 | bbb |
| 3 | post1 | 2018 | ccc |
+----+-------+------+------+
参见:http://rextester.com/HXQ91572
对于 MySQL 的更新版本或类似 MariaDb 的变体,您可以简单地使用 row_number() over()
,如下所示:
SELECT
post, `date`, tags
FROM (
SELECT
t.post
, t.`date`
, t.tags
, row_number() over(partition by t.tags order by t.`date`DESC) as RowNumber
FROM table1 t
) d
WHERE RowNumber = 1
ORDER BY
tags, `date`
;
在上面的两个查询变体中,您根据数据的排序为每个 "first row" 计算值 1。一旦需要的行引用已知,您就可以过滤掉任何不需要的行。
我有一个 table 这样的:
post | date | tags
--------+-----------+-------
post3 | 2016 | bbb
post1 | 2018 | aaa
post2 | 2017 | ccc
post1 | 2018 | bbb
post3 | 2016 | aaa
post2 | 2017 | bbb
post2 | 2017 | bbb
post1 | 2018 | ccc
post3 | 2016 | ccc
我想得到以下结果:
post | date | tags
------- +---------- +--------
post1 | 2018 | aaa
post2 | 2017 | bbb
post3 | 2016 | ccc
换句话说,我想要做的是:首先,根据列(在本例中是日期列)对 table 进行排序。其次,根据另一列(在本例中为列标签)进行分组。最后,我希望 post 列的结果不会重复。
第一部分和第二部分我知道怎么做。我应用下面的查询...
SELECT post, `date`, tag
FROM tabela AS t1
WHERE t1.`date` = (
SELECT MAX(t2.`date`)
FROM tabela AS t2
WHERE t1.tag = t2.tag
)
...我得到以下结果:
post | data | tags
------- +---------- +--------
post1 | 2018 | aaa
post1 | 2018 | bbb
post1 | 2018 | ccc
如您所见,问题是 post1 对所有标签重复。我不希望这种情况发生。我希望根据日期列给出的最高值智能地填充所有行,但不在 post 列中重复。
我该怎么做?
PS: 抱歉英文错误,我不是美国人。
在 v8x 之前的 MySQL 版本中,您可以像这样使用变量:
SELECT
post, `date`, tags
FROM (
SELECT
@row_num :=IF(@prev_value=t.tags, @row_num + 1, 1) AS RowNumber
, t.post
, t.`date`
, t.tags
, @prev_value := t.tags
FROM mytable t
CROSS JOIN (SELECT @row_num :=1, @prev_value :='') vars
ORDER BY
t.tags
, t.`date` DESC
) d
WHERE RowNumber = 1
ORDER BY
tags, `date`
;
+----+-------+------+------+
| | post | date | tags |
+----+-------+------+------+
| 1 | post1 | 2018 | aaa |
| 2 | post1 | 2018 | bbb |
| 3 | post1 | 2018 | ccc |
+----+-------+------+------+
参见:http://rextester.com/HXQ91572
对于 MySQL 的更新版本或类似 MariaDb 的变体,您可以简单地使用 row_number() over()
,如下所示:
SELECT
post, `date`, tags
FROM (
SELECT
t.post
, t.`date`
, t.tags
, row_number() over(partition by t.tags order by t.`date`DESC) as RowNumber
FROM table1 t
) d
WHERE RowNumber = 1
ORDER BY
tags, `date`
;
在上面的两个查询变体中,您根据数据的排序为每个 "first row" 计算值 1。一旦需要的行引用已知,您就可以过滤掉任何不需要的行。