Не использовать UNION и вывести 2 последних значения пользователя

Есть база юзеров и их добавленные ссылки с фиксацией времени. Задача - средствами SQL вывести по каждому юзеру по 2 последних добавленных ссылки. UNION не выход, по словам куратора. Через PHP я мог бы получить список пользователей и по каждому пользователю сделать запрос с LIMIT 2, но это слишком много нагрузки. У куратора есть решение, но он не делится)

Гугл тоже не делится

Пробовал так: SELECT id, user_id, url, MAX(add_date) FROM test GROUP BY user_id; Но здесь выводиться только 1 результат по сгруппированному user_id, а нужно 2.

Вот пример базы:

Пример базы

Вот что нужно получить:

Нужный результат


Ответы (2 шт):

Автор решения: Andrew Nikolaev

В ранних версиях MySQL это может не работать, но в современных работает.

CREATE TABLE test (id INT PRIMARY KEY AUTO_INCREMENT, user_id INT, url CHAR(255), add_date DATE);

INSERT test (user_id, url, add_date) VALUES(1, "url1", NOW());
INSERT test (user_id, url, add_date) VALUES(2, "url1", NOW());
INSERT test (user_id, url, add_date) VALUES(1, "url2", NOW());
INSERT test (user_id, url, add_date) VALUES(2, "url2", NOW());
INSERT test (user_id, url, add_date) VALUES(2, "url3", NOW());
INSERT test (user_id, url, add_date) VALUES(3, "url1", NOW());

SELECT SQ.* FROM
(
    SELECT
        RANK() OVER ( PARTITION BY t1.user_id ORDER BY t1.id DESC) AS Rnk,  
        user_id,
        URL,
        add_date
    FROM test t1
) SQ
WHERE SQ.Rnk <= 2
ORDER BY SQ.user_id
          
/*DROP TABLE test */

Надеюсь, я смог Вам помочь)

→ Ссылка
Автор решения: Виктор Карев

Вот вариант через кучу джойнов:

select test.* from test
left join
(
select t2.user_id, max(t2.id) id2, t.id id1
from test t2
right join
(select t1.user_id, max(t1.id) id from test t1 group by t1.user_id) t
on (t.user_id = t2.user_id and t2.id < t.id)
group by user_id
) t3
on(test.id = t3.id1 or test.id = t3.id2)
where !isnull(id1)
order by test.user_id, test.id
→ Ссылка