根据 MySQL 中的多列获取最大行
Get greatest rows based on multiple columns in MySQL
我有一个 table 看起来像:
id | title | value | language
---+-------+-------+---------
1 | a | 1800 | NULL
2 | a | 1900 | NULL
3 | b | 1700 | NULL
4 | b | 1750 | NULL
5 | b | 1790 | 1
6 | c | 1892 | NULL
7 | c | 1900 | 1
8 | c | 1910 | 2
9 | d | 3020 | NULL
想要得到以下结果:
id | title | value | language
---+-------+-------+---------
2 | a | 1900 | NULL
4 | b | 1750 | NULL
5 | b | 1790 | 1
6 | c | 1892 | NULL
7 | c | 1900 | 1
8 | c | 1910 | 2
9 | d | 3020 | NULL
重点是 select 每个标题的每种语言的值列中的最大值 - 最大的是最新的。其次,想避免像 MAX、DISTINCT 或 GROUP-BY 这样的聚合函数,因为我正在使用 MERGE 算法构建 MySQL 视图,并且不想最终创建一个临时的 table (参见 https://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html 的底部部分)。
到目前为止这可行,但每个标题只有 returns 最大行:
SELECT t1.title
FROM table t1
LEFT OUTER JOIN table t2
ON t1.title = t2.title
AND t1.value < t2.value
WHERE t2.title IS NULL
如何创建一个像上面的结果那样考虑语言的结果?谢谢
此答案假设您使用的是 MySQL 8+,您的查询将变得非常容易。 MySQL8及以后版本支持解析函数,为解决此类问题而加入
我们可以在这里尝试使用 ROW_NUMBER
:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY title, language ORDER BY value DESC) rn
FROM yourTable
)
SELECT id, title, value, language
FROM cte
WHERE rn = 1;
MySQL 的早期版本有一种方法可以处理此问题,但它需要用户变量,而且往往非常丑陋。因此,如果您希望有很多与此类似的查询,可以考虑升级。
这应该能满足您的需求。
SELECT t1.title, t1.value, t1.language
FROM [Table] t1
LEFT OUTER JOIN [Table] t2 ON
t1.title = t2.title AND
(IFNULL(t1.language, '') = IFNULL(t2.language, ''))
WHERE
t1.value > t2.value;
你可以用 NOT EXISTS
:
select t.*
from tablename t
where not exists (
select 1 from tablename
where
title = t.title and
coalesce(language, 0) = coalesce(t.language, 0) and
value > t.value
)
参见demo。
结果:
| id | title | value | language |
| --- | ----- | ----- | -------- |
| 2 | a | 1900 | NULL |
| 4 | b | 1750 | NULL |
| 5 | b | 1790 | 1 |
| 6 | c | 1892 | NULL |
| 7 | c | 1900 | 1 |
| 8 | c | 1910 | 2 |
| 9 | d | 3020 | NULL |
我有一个 table 看起来像:
id | title | value | language
---+-------+-------+---------
1 | a | 1800 | NULL
2 | a | 1900 | NULL
3 | b | 1700 | NULL
4 | b | 1750 | NULL
5 | b | 1790 | 1
6 | c | 1892 | NULL
7 | c | 1900 | 1
8 | c | 1910 | 2
9 | d | 3020 | NULL
想要得到以下结果:
id | title | value | language
---+-------+-------+---------
2 | a | 1900 | NULL
4 | b | 1750 | NULL
5 | b | 1790 | 1
6 | c | 1892 | NULL
7 | c | 1900 | 1
8 | c | 1910 | 2
9 | d | 3020 | NULL
重点是 select 每个标题的每种语言的值列中的最大值 - 最大的是最新的。其次,想避免像 MAX、DISTINCT 或 GROUP-BY 这样的聚合函数,因为我正在使用 MERGE 算法构建 MySQL 视图,并且不想最终创建一个临时的 table (参见 https://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html 的底部部分)。
到目前为止这可行,但每个标题只有 returns 最大行:
SELECT t1.title
FROM table t1
LEFT OUTER JOIN table t2
ON t1.title = t2.title
AND t1.value < t2.value
WHERE t2.title IS NULL
如何创建一个像上面的结果那样考虑语言的结果?谢谢
此答案假设您使用的是 MySQL 8+,您的查询将变得非常容易。 MySQL8及以后版本支持解析函数,为解决此类问题而加入
我们可以在这里尝试使用 ROW_NUMBER
:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY title, language ORDER BY value DESC) rn
FROM yourTable
)
SELECT id, title, value, language
FROM cte
WHERE rn = 1;
MySQL 的早期版本有一种方法可以处理此问题,但它需要用户变量,而且往往非常丑陋。因此,如果您希望有很多与此类似的查询,可以考虑升级。
这应该能满足您的需求。
SELECT t1.title, t1.value, t1.language
FROM [Table] t1
LEFT OUTER JOIN [Table] t2 ON
t1.title = t2.title AND
(IFNULL(t1.language, '') = IFNULL(t2.language, ''))
WHERE
t1.value > t2.value;
你可以用 NOT EXISTS
:
select t.*
from tablename t
where not exists (
select 1 from tablename
where
title = t.title and
coalesce(language, 0) = coalesce(t.language, 0) and
value > t.value
)
参见demo。
结果:
| id | title | value | language |
| --- | ----- | ----- | -------- |
| 2 | a | 1900 | NULL |
| 4 | b | 1750 | NULL |
| 5 | b | 1790 | 1 |
| 6 | c | 1892 | NULL |
| 7 | c | 1900 | 1 |
| 8 | c | 1910 | 2 |
| 9 | d | 3020 | NULL |