问题
With a table like:
idx type dat
0 a foo1
1 b foo2
2 c foo3
3 a foo4
4 b foo5
5 c foo6
6 a foo7
7 b foo8
8 c foo9
How can i get the first and last data of each type:
for example:
a foo1 foo7
b foo2 foo8
c foo3 foo9
I have tried this query, but its way to slow, even with indexes on idx and type:
select mins.type, mins.dat, mytable.dat from mytable
--get the maximums
inner join
(select max(idx) as maxidx from mytable group by type) as a
on a.maxidx = mytable.idx
--join the maximums to the minimums
inner join
--get the minimums
(select * from mytable inner join (select min(idx) as minidx from mytable group by type) as b
on b.minidx = mytable.idx ) as mins
on issues.type = mins.type
The join of on issues.type = mins.type seems to be what is slowing it down so much because mins.type is derived and not indexed?
回答1:
Use mysql's "funky" functionality of a GROUP BY
without aggregating the other columns, which simply returns the first row of the group. The problem then becomes getting the rows into the correct order before using this functionality, typically by using an aliased query.
This approach avoids any correlated subqueries (queries per row) and needs just two passes over the table (one for each direction of ordering):
select x2.type, x2.dat as first_dat, y2.dat as last_dat
from (select *
from (select type, dat
from so8735514
order by 1, 2) x1
group by 1) x2
join (select *
from (select type, dat
from so8735514
order by 1, 2 desc) y1
group by 1) y2 on y2.type = x2.type;
Test code:
create table so8735514 (idx int, type text, dat text);
insert into so8735514 values
(0, 'a', 'foo1'),
(1, 'b', 'foo2'),
(2, 'c', 'foo3'),
(3, 'a', 'foo4'),
(4, 'b', 'foo5'),
(5, 'c', 'foo6'),
(6, 'a', 'foo7'),
(7, 'b', 'foo8'),
(8, 'c', 'foo9');
Output:
+------+-----------+----------+
| type | first_dat | last_dat |
+------+-----------+----------+
| a | foo1 | foo7 |
| b | foo2 | foo8 |
| c | foo3 | foo9 |
+------+-----------+----------+
来源:https://stackoverflow.com/questions/8735514/mysql-join-first-and-last-records-by-group-type