假设我正在寻找第二高的记录。
样本表:
CREATE TABLE `my_table` (
`id` int(2) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`value` int(10),
PRIMARY KEY (`id`)
);
INSERT INTO `my_table` (`id`, `name`, `value`) VALUES (NULL, 'foo', '200'), (NULL, 'bar', '100'), (NULL, 'baz', '0'), (NULL, 'quux', '300');
第二高的值是foo
。有多少种方法可以得到这个结果?
明显的例子是:
SELECT name FROM my_table ORDER BY value DESC LIMIT 1 OFFSET 1;
您能想到其他例子吗?
我正在尝试这个,但不支持LIMIT & IN/ALL/ANY/SOME subquery
。
SELECT name FROM my_table WHERE value IN (
SELECT MIN(value) FROM my_table ORDER BY value DESC LIMIT 1
) LIMIT 1;
答案 0 :(得分:2)
Eduardo在标准SQL中的解决方案
select *
from (
select id,
name,
value,
row_number() over (order by value) as rn
from my_table t
) t
where rn = 1 -- can pick any row using this
这适用于除MySQL以外的任何现代DBMS。此解决方案通常比使用子选择的解决方案更快。它也可以轻松返回第2行,第3行......(同样,这也可以通过Eduardo的解决方案实现)。
它也可以调整为按组计数(添加partition by
),这样就可以用相同的模式解决“每组最大n”问题。
这是一个可以使用的SQLFiddle:http://sqlfiddle.com/#!12/286d0/1
答案 1 :(得分:1)
您可以像这样使用内联初始化:
select * from (
select id,
name,
value,
@curRank := @curRank + 1 AS rank
from my_table t, (SELECT @curRank := 0) r
order by value desc
) tb
where tb.rank = 2
答案 2 :(得分:1)
SELECT name
FROM my_table
WHERE value < (SELECT max(value) FROM my_table)
ORDER BY value DESC
LIMIT 1
SELECT name
FROM my_table
WHERE value = (
SELECT min(r.value)
FROM (
SELECT name, value
FROM my_table
ORDER BY value DESC
LIMIT 2
) r
)
LIMIT 1
答案 3 :(得分:1)
这仅适用于完全第二高:
SELECT * FROM my_table two
WHERE EXISTS (
SELECT * FROM my_table one
WHERE one.value > two.value
AND NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
)
LIMIT 1
;
这个模拟了没有它们的平台的窗口函数rank()。它也可以适用于排名&lt;&gt; 2通过改变一个常数:
SELECT one.*
-- , 1+COALESCE(agg.rnk,0) AS rnk
FROM my_table one
LEFT JOIN (
SELECT one.id , COUNT(*) AS rnk
FROM my_table one
JOIN my_table cnt ON cnt.value > one.value
GROUP BY one.id
) agg ON agg.id = one.id
WHERE agg.rnk=1 -- the aggregate starts counting at zero
;
两个解决方案都需要功能性自联接(我不知道mysql是否允许它们,IIRC只有在表是更新或删除的目标时才会禁止它们)
下面的内容不需要窗口函数,但使用递归查询来枚举排名:
WITH RECURSIVE agg AS (
SELECT one.id
, one.value
, 1 AS rnk
FROM my_table one
WHERE NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
UNION ALL
SELECT two.id
, two.value
, agg.rnk+1 AS rnk
FROM my_table two
JOIN agg ON two.value < agg.value
WHERE NOT EXISTS (
SELECT * FROM my_table nx
WHERE nx.value > two.value
AND nx.value < agg.value
)
)
SELECT * FROM agg
WHERE rnk = 2
;
(显然,递归查询在mysql中不起作用)