尝试在 MySQL 中模拟 ROW_NUMBER OVER PARTITION:http ://www.sqlfiddle.com/#!2/fd8b5/4
鉴于此数据:
create table sentai(
band varchar(50),
member_name varchar(50),
member_year int not null
);
insert into sentai(band, member_name, member_year) values
('BEATLES','JOHN',1960),
('BEATLES','PAUL',1961),
('BEATLES','GEORGE',1962),
('BEATLES','RINGO',1963),
('VOLTES V','STEVE',1970),
('VOLTES V','MARK',1971),
('VOLTES V','BIG BERT',1972),
('VOLTES V','LITTLE JOHN',1973),
('VOLTES V','JAMIE',1964),
('ERASERHEADS','ELY',1990),
('ERASERHEADS','RAYMUND',1991),
('ERASERHEADS','BUDDY',1992),
('ERASERHEADS','MARCUS',1993);
对象,找到每个乐队的所有三个最近的成员。
首先,我们必须根据大多数年份在每个成员上放置一个 row_number(通过降序)
select *,
@rn := @rn + 1 as rn
from (sentai s, (select @rn := 0) as vars)
order by s.band, s.member_year desc;
输出:
| BAND | MEMBER_NAME | MEMBER_YEAR | @RN := 0 | RN |
|-------------|-------------|-------------|----------|----|
| BEATLES | RINGO | 1963 | 0 | 1 |
| BEATLES | GEORGE | 1962 | 0 | 2 |
| BEATLES | PAUL | 1961 | 0 | 3 |
| BEATLES | JOHN | 1960 | 0 | 4 |
| ERASERHEADS | MARCUS | 1993 | 0 | 5 |
| ERASERHEADS | BUDDY | 1992 | 0 | 6 |
| ERASERHEADS | RAYMUND | 1991 | 0 | 7 |
| ERASERHEADS | ELY | 1990 | 0 | 8 |
| VOLTES V | LITTLE JOHN | 1973 | 0 | 9 |
| VOLTES V | BIG BERT | 1972 | 0 | 10 |
| VOLTES V | MARK | 1971 | 0 | 11 |
| VOLTES V | STEVE | 1970 | 0 | 12 |
| VOLTES V | JAMIE | 1964 | 0 | 13 |
然后,当成员在不同的频段时,我们重置行号:
select *,
@rn := IF(@pg = s.band, @rn + 1, 1) as rn,
@pg := s.band
from (sentai s, (select @pg := null, @rn := 0) as vars)
order by s.band, s.member_year desc;
输出:
| BAND | MEMBER_NAME | MEMBER_YEAR | @PG := NULL | @RN := 0 | RN | @PG := S.BAND |
|-------------|-------------|-------------|-------------|----------|----|---------------|
| BEATLES | RINGO | 1963 | (null) | 0 | 1 | BEATLES |
| BEATLES | GEORGE | 1962 | (null) | 0 | 2 | BEATLES |
| BEATLES | PAUL | 1961 | (null) | 0 | 3 | BEATLES |
| BEATLES | JOHN | 1960 | (null) | 0 | 4 | BEATLES |
| ERASERHEADS | MARCUS | 1993 | (null) | 0 | 1 | ERASERHEADS |
| ERASERHEADS | BUDDY | 1992 | (null) | 0 | 2 | ERASERHEADS |
| ERASERHEADS | RAYMUND | 1991 | (null) | 0 | 3 | ERASERHEADS |
| ERASERHEADS | ELY | 1990 | (null) | 0 | 4 | ERASERHEADS |
| VOLTES V | LITTLE JOHN | 1973 | (null) | 0 | 1 | VOLTES V |
| VOLTES V | BIG BERT | 1972 | (null) | 0 | 2 | VOLTES V |
| VOLTES V | MARK | 1971 | (null) | 0 | 3 | VOLTES V |
| VOLTES V | STEVE | 1970 | (null) | 0 | 4 | VOLTES V |
| VOLTES V | JAMIE | 1964 | (null) | 0 | 5 | VOLTES V |
然后我们只选择每个乐队最近的三个成员:
select x.band, x.member_name, x.member_year
from
(
select *,
@rn := IF(@pg = s.band, @rn + 1, 1) as rn,
@pg := s.band
from (sentai s, (select @pg := null, @rn := 0) as vars)
order by s.band, s.member_year desc
) as x
where x.rn <= 3
order by x.band, x.member_year desc;
输出:
| BAND | MEMBER_NAME | MEMBER_YEAR |
|-------------|-------------|-------------|
| BEATLES | RINGO | 1963 |
| BEATLES | GEORGE | 1962 |
| BEATLES | PAUL | 1961 |
| ERASERHEADS | MARCUS | 1993 |
| ERASERHEADS | BUDDY | 1992 |
| ERASERHEADS | RAYMUND | 1991 |
| VOLTES V | LITTLE JOHN | 1973 |
| VOLTES V | BIG BERT | 1972 |
| VOLTES V | MARK | 1971 |
虽然 MySQL 上还没有窗口函数(例如 ROW_NUMBER OVER PARTITION),但只需用变量模拟它。请让我们知道这是否比光标方法快
它在具有窗口功能的 RDBMS 上的样子:http ://www.sqlfiddle.com/#!1/fd8b5/6
with member_recentness as
(
select row_number() over each_band as recent, *
from sentai
window each_band as (partition by band order by member_year desc)
)
select *
from member_recentness
where recent <= 3;
输出:
| RECENT | BAND | MEMBER_NAME | MEMBER_YEAR |
|--------|-------------|-------------|-------------|
| 1 | BEATLES | RINGO | 1963 |
| 2 | BEATLES | GEORGE | 1962 |
| 3 | BEATLES | PAUL | 1961 |
| 1 | ERASERHEADS | MARCUS | 1993 |
| 2 | ERASERHEADS | BUDDY | 1992 |
| 3 | ERASERHEADS | RAYMUND | 1991 |
| 1 | VOLTES V | LITTLE JOHN | 1973 |
| 2 | VOLTES V | BIG BERT | 1972 |
| 3 | VOLTES V | MARK | 1971 |