SQL выбирает n-й член группы
Если у меня есть таблица USER, например
class | age
--------------
1 20
3 56
2 11
1 12
2 20
Затем я могу легко получить младшего пользователя в каждом классе через
select class, min(age)
from user
group by class;
Аналогично, заменив min max, я могу получить самый старый. Но как я могу получить 10-ю младшую (или самую старую) в каждом классе? Кстати, я использую MySql v.5.0.
Приветствия,
Ответы
Ответ 1
SELECT a.class,
(
SELECT b.age
FROM users b
WHERE b.class = a.class
ORDER BY age
LIMIT 1,1
) as age
FROM users a
GROUP BY a.class
Получил второго младшего в каждом классе. Если вы захотите 10-го юнита, вы бы сделали LIMIT 9,1
, и если бы вы захотели получить 10-е место, вы сделали бы ORDER BY age DESC
.
Ответ 2
Здесь N
представлена запись Nth
oldest
SELECT *
FROM users k
WHERE N = (SELECT
COUNT( DISTINCT age)
FROM users u
WHERE k.age >= u.age
AND k.class = u.class
GROUP BY u.class)
и дает Nth
запись youngest
SELECT *
FROM users k
WHERE N = (SELECT
COUNT(DISTINCT age)
FROM users u
WHERE k.age <= u.age
AND k.class = u.class
GROUP BY u.class)
Ответ 3
Единственный независимый sql-путь (даже если у вас нет подзапросов mysql < 5)
select u1.class, u1.age, count(*) from user u1 join user u2
on u1.class = u2.class and u1.age >= u2.age
group by u1.class, u1.age
having count(*) = [number]
получает [число] самых старых в классе
select u1.class, u1.age, count(*) from user u1 join user u2
on u1.class = u2.class and u1.age <= u2.age
group by u1.class, u1.age
having count(*) = [number]
получает вас [число] младший в классе
Если два человека имеют одинаковый возраст, он может не работать, поскольку оба возвращаются. Если вы хотите только вернуть один из них, вам понадобится уникальный ключ, и запрос будет более сложным.
Ответ 4
В SQL Server довольно легко:
select
*
from(
select
*,
row_number() over(order by age asc) as eldest
from class order by age asc) a
where a.eldest = 10
Следуя этому шаблону, для MySQL, я думаю, вы хотели бы посмотреть на это: http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/
Ответ 5
SELECT идентификатор пользователя,
класс,
возраст,
(SELECT COUNT (1) FROM пользователя
WHERE class= c.class AND age > u.age
) AS oldercount
ОТ пользователя AS u
WHERE oldercount = 9 Класс GROUP BY
или
SELECT userid,
класс,
возраст
ОТ пользователя AS u
WHERE (SELECT COUNT (1) FROM class WHERE class= c.class AND age > u.age) = 9
Класс GROUP BY
Ответ 6
Любой ответ, который присоединяется к таблице на нем, будет создавать квадратный закон...
- a JOIN b ON a.class = b.class AND a.age >= b.age
- on average the >= condition will be true for half the class
- 6 people in a class
->6*6/2 = 18
- 10 people in a class
->10*10/2 = 50
-> very rapid growth
По мере роста размеров таблиц производительность быстро ухудшится. Если вы держите вещи маленькими, и они не будут расти, это проблема? Ваш звонок там...
Альтернатива включает больше кода, но растет линейно...
- Сначала вставьте все записи в новую таблицу с полем IDENTITY, упорядоченным по классу, а затем Age
- Теперь для каждого класса найдите MIN (id)
- Теперь для каждого класса rinf запись, где is = MIN (id) + 8 (для 9-го старшего)
Существует много способов сделать последние 2 шага. Я лично использовал бы...
SELECT
[USER_WITH_IDS].id,
[USER_WITH_IDS].class,
[USER_WITH_IDS].age
FROM
[USER_WITH_IDS]
WHERE
[USER_WITH_IDS].id = (
SELECT
MIN([min].ID) + 8
FROM
[USER_WITH_IDS] AS [min]
WHERE
[min].class = [USER_WITH_IDS].class
)
Что это дает...
- Один проход для создания новых идентификаторов
- Один проход, чтобы получить MIN (id) для каждого класса
-
Один проход для получения требуемых записей
-
И в зависимости от того, насколько хорош оптимизатор, используя индекс (class then id), он сможет объединить последние 2 прохода в 1 проход.
2 или 3 прохода, независимо от того, насколько большой размер таблицы или класса. Линейный, а не квадратный закон...