2016-09-15 5 views
3

я нашел существующие вопросы с последней/низкой одной строки на несколько полей или последние п строк по одному полю, а не два вместеMySql - выберите верхние п строки, сгруппированные по 2 колонке

мне нужно построить 2 запросы, используя этот пример таблицы (аналогичную this question)

CREATE TABLE lap_data (
    id   int(1)  NOT NULL, 
    track_id  int(1)  NOT NULL, 
    user_id  int(1)  NOT NULL, 
    lap_time  time  NOT NULL, 
    lap_status tinyint(1) NOT NULL, 
    PRIMARY KEY (id) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

INSERT INTO `lap_data` (`id`, `track_id`, `user_id`, `lap_time`, `lap_status`) VALUES 
(1, 1, 1, '04:18:23', 1), 
(2, 2, 2, '01:09:54', 1), 
(3, 2, 1, '01:05:30', 1), 
(4, 1, 2, '04:17:02', 1), 
(5, 3, 2, '01:13:10', 1), 
(6, 4, 1, '01:36:59', 0), 
(7, 3, 2, '01:18:10', 1), 
(8, 2, 3, '01:06:42', 1), 
(9, 1, 1, '04:16:12', 1), 
(10, 1, 2, '04:18:12', 1), 
(11, 2, 3, '01:03:20', 1), 
(12, 2, 1, '01:08:13', 1), 
(13, 2, 1, '01:09:44', 1), 
(14, 3, 2, '01:14:10', 1), 
(15, 3, 2, '01:17:20', 1), 
(16, 4, 1, '01:36:23', 1), 
(17, 2, 1, '01:11:34', 1); 

Query 1:

  • Я хочу, чтобы верхние 2 результатов по lap_time - на дорожку, на одного пользователя
    • так, если данный user_id 20 записей распространяются на 3 дорожки ...
      • Я хотел бы ожидать 6 результатов что user_id
      • или 5, если один из этих треков имеет только одну запись
    • то же самое время на круге на 2-х различных направлениях, оба должны быть отображены, не появляются только один раз
  • Я хочу использовать WHERE user_id IN (..) для части 1
  • заказанного данной области, т.е. lap_time
  • где lap_status = 1

Это я запрос мы использовали в другом месте для сбора двух последних записей определенного типа, который наиболее близок к тому, что мне кажется необходимым, изменен в этом примере .. хотя и незавершенный, как в другом случае, он собирал только 2 последних строки для каждого user_id .. здесь мне нужно, чтобы он также учитывал track_id

SELECT 
* 
FROM (
    SELECT 
    t.id, 
    t.track_id, 
    t.user_id, 
    t.lap_time, 
    t.lap_status, 
    @row:=case WHEN @prev=user_id THEN @row ELSE 0 END +1 rn, 
    @prev:=user_id 
    FROM `lap_data` t 
    CROSS JOIN (SELECT @row:=0, @prev:=null) c 
    WHERE t.user_id IN (1,2) 
    ORDER BY user_id, id DESC 
) src 
WHERE rn <= 2 
ORDER BY lap_time DESC 

Запрос 1 Желаемый результат: (ГДЕ идентификатор_пользователя В (1,2))

 
| id | track_id | user_id | lap_time | lap_status | 
-------------------------------------------------------------- 
| 9 |   1 |  1 | 04:16:12 |   1 | 
| 1 |   1 |  1 | 04:18:23 |   1 | 
| 3 |   2 |  1 | 01:05:30 |   1 | 
| 12 |   2 |  1 | 01:08:13 |   1 | 
| 16 |   4 |  1 | 01:36:23 |   1 | 
| 6 |   4 |  1 | 01:36:59 |   1 | 
| 4 |   1 |  2 | 04:17:02 |   1 | 
| 10 |   1 |  2 | 04:18:12 |   1 | 
| 2 |   2 |  2 | 01:09:54 |   1 | 
| 5 |   3 |  2 | 01:13:10 |   1 | 
| 14 |   3 |  2 | 01:14:10 |   1 | 

Запрос 2:

  • Я хочу, чтобы получить обратную выше , для одного пользователя
    • т.е. остальная часть результатов, за исключением f рвые два, для всего конкретного user_id

Запрос 2 Желаемый результат: (WHERE user_id = '1')

 
| id | track_id | user_id | lap_time | lap_status | 
-------------------------------------------------------------- 
| 13 |   2 |  1 | 01:09:44 |   1 | 
| 17 |   2 |  1 | 01:11:34 |   1 | 

Любые предложения? благодаря!

+0

Вы еще что-нибудь пробовали? –

+0

@Strawberry добавил ребята, спасибо за подсказку –

+0

Ваши усилия выглядят очень близко - вы уверены, что не можете понять, как это приспособить? – Strawberry

ответ

1

MYSQL Версия для моего предыдущего ответа:

SELECT 
lt.id, 
lt.user_id, 
lt.track_id, 
lt.lap_status, 
lt.lap_time 
FROM (
SELECT id, 
    user_id, 
    track_id, 
    lap_status, 
    lap_time, 
    CASE WHEN track_id = @prevTrackId AND user_id = @prevUserId THEN @curRank := @curRank + 1 ELSE @curRank := 1 END Rank, 
    @prevTrackId := track_id, 
    @prevUserId := user_id 
FROM lap_data, (SELECT @curRank := 0, @prevTrackId := 1, @prevUserId := 1) r 
ORDER BY user_id,track_id,lap_time ASC 
) lt 
WHERE Rank <= 2 
+0

спасибо за сообщение другой версии .. к сожалению это возвращает 4 строки для user_id = 1 и track_id = 2 –

+0

Хорошо, я забыл назначить prevTrackId и prevUserId текущей строке. Попробуйте отредактировать код выше. – darrell

+0

Я по-прежнему проверяю различные варианты использования, но похоже, что это делает работу ... спасибо большое! –

-1

Запрос 1:

SELECT lt.id,lt.user_id,lt.track_id,lt.lap_status,lt.lap_time 
FROM (
    SELECT id,user_id,track_id,lap_status,lap_time,Rank() 
    over (Partition BY user_id,track_id 
    ORDER BY lap_time ASC) AS Rank 
    FROM lap_data 
    WHERE user_id IN (1,2) 
) lt WHERE Rank <= 2 

Запрос 2: Просто просто выбрать все записи, которые NOT IN Query 1. (предполагается, что идентификатор является первичным ключом вашей таблицы, которые вы даже не установили первичный ключ для таблицы lap_data)

SELECT * FROM lap_data 
    WHERE id NOT IN 
    (SELECT lt.id 
    FROM (
     SELECT id,Rank() 
     over (Partition BY user_id,track_id 
     ORDER BY lap_time ASC) AS Rank 
     FROM lap_data 
     WHERE user_id = 1 
    ) lt WHERE Rank <= 2) 
+0

спасибо, к сожалению, я получаю сообщение об ошибке при первом запросе: у вас есть ошибка в синтаксисе SQL; проверьте руководство, соответствующее версии вашего сервера MySQL, для правильного синтаксиса для использования рядом с ним (Partition BY user_id, track_id ORDER BY lap_time ASC) AS Rank FROM la 'в строке 4 –

+0

Ха, извините, я предоставил решение в MSSQL вместо MySQL, мой плохой. – darrell

0

Этот запрос делает один важный (и вполне вероятно, ошибочно) предположение - что, что привет ghest track_id предыдущего пользователя выше (или, по крайней мере, отличается от) младшего track_id следующего пользователя.

Если это не так, то вам может понадобиться для хранения других переменного, или основания «предыдущий» на конкатенации двух значений ...

SELECT x.id 
     , x.track_id 
     , x.user_id 
     , x.lap_time 
     , x.lap_status 
    FROM 
     (SELECT l.* 
      , CASE WHEN @prev = track_id THEN @i:[email protected]+1 ELSE @i:=1 END rank 
      , @prev:=track_id prev 
      FROM lap_data l 
      , (SELECT @prev:=null,@i:=0) vars 
     WHERE user_id IN(1,2) 
     ORDER 
      BY user_id 
      , track_id 
      , lap_time 
    ) x 
    WHERE x.rank <=2 
    ORDER 
    BY user_id 
     , track_id 
     , lap_time; 
+0

Спасибо за это .. track_id может быть одним и тем же или другим к сожалению, т. Е. Может иметь несколько пользователей с записями только для трека 2, например ... Между сохранением другого значения и конкатенированием обоих в prev, что, вероятно, будет быстрый? –

+0

Дополнительная переменная лучше, независимо - но я нахожу, что эту логику легче писать как вложенные IF, а не вложенные операторы CASE – Strawberry

+0

Не могли бы вы отправить сообщение с двумя полями в качестве пользовательских значений? Я понятия не имею, как подойти к ней ..... (Я на самом деле ошеломлен. Мне удалось правильно предположить, что либо необходимо было быть конкатенированным, либо отслеживать два поля) –

0
select id,track_id,user_id,lap_status,lap_time from (
select @rank:=if(@prev_cat=user_id,@rank+1,1) as rank,id,user_id,track_id,lap_status,lap_time,@prev_cat:=user_id 
from lap_data,(select @rank:=0, @prev_cat:="")t 
where user_id IN(1,2) order by track_id, user_id desc 
) temp 
    where temp.rank<=2 
+0

это возвращает четыре строки с track_id = 2 и user_id = 1 .. я хотел только две строки –

+0

Пожалуйста, проверьте сейчас –

Смежные вопросы