November 2019

S M T W T F S
      12
34 5 678 9
10111213141516
17181920212223
24252627282930

Style Credit

Expand Cut Tags

No cut tags
Wednesday, September 15th, 2010 06:20 pm

Для DBA её тоже можно применять. На самом начальном этапе, потому что если кандидат не смог навскидку ответить, то он никакой не DBA, а чмо какое-то. А вот программист такого может сразу не знать, но придумать должен, если умный.

Итак. Есть табличка foo, в которой содержатся данные об игроках по дням в следующем виде: date, user_id, nickname и кучка других данных за указанный день, которые нас не интересуют. Игрок идентифицируется по user_id и участвует в игре под псевдонимом nickname. В теории nickname у игрока меняться не должен, а на практике может, поэтому в разные дни у одного user_id может быть разный nickname. Для каждого user_id за каждую дату может быть не более одной записи, потому что nickname в течение дня меняться не может, к счастью.

Задача: выбрать одним запросом (можно с подзапросами) полный список всех user_id и для каждого из них один-единственный nickname – тот, под которым игрок играл последний раз.

Классический ответ под катом, но если кто знает другие варианты – welcome.

SELECT a.userid, a.nickname
FROM foo a
WHERE a.date = (SELECT MAX(b.date) FROM foo b WHERE b.user_id = a.user_id)

Оригинал этой записи. Комментировать можно тут или там.

Любые материалы из этого блога запрещается использовать на сайте livejournal.ru в любой форме и любом объёме

Wednesday, September 15th, 2010 05:35 pm (UTC)
Вроде сработает так, не проверял, но если и опечатался, то идею можно довести до ума.

select t1.user_id, t1.nickname from t as t1 left join t t2 on t1.user_id=t2.user_id and t1.date<t2.date where t2.user_id is null
Wednesday, September 15th, 2010 05:37 pm (UTC)
Классический лучше моего.
Wednesday, September 15th, 2010 05:39 pm (UTC)
Не, так не получится. join on t1.user_id=t2.user_id никак не сочетается с where t2.user_id is null
Wednesday, September 15th, 2010 05:41 pm (UTC)
В mysql такая конструкция работает для left join и я всю жизнь думал, что это по стандарту SQL.
Wednesday, September 15th, 2010 08:20 pm (UTC)
Да, работает. Мне никогда не приходило в голову делать join по неравенству
Wednesday, September 15th, 2010 08:53 pm (UTC)
это стандартная практика заставить субд сделать semi-join http://www.sql.ru/forum/actualthread.aspx?tid=575673#5934896 что бы найти записи из t1, отсутствующие в t2
Wednesday, September 15th, 2010 06:32 pm (UTC)
where t2.user_id is null это post-join предикат. Все будет хорошо.
Wednesday, September 15th, 2010 06:35 pm (UTC)
select a.userid, (SELECT first 1 b.nickname FROM foo b WHERE b.user_id = a.user_id order by b.date desc)
from
(SELECT distinct userid FROM foo) a
Wednesday, September 15th, 2010 08:25 pm (UTC)
Тоже вариант, но по-моему, тут многовато select'ов. Нельзя его как-нибудь сократить?
Wednesday, September 15th, 2010 08:47 pm (UTC)
зачем?
Для абстрактной красоты и пуризма рулит твой вариант.
Для практики, я управлюсь в проход/заход в foo, оракле с помощью olap синтаксиса создается окно partition by nickname, в окне записи упорядочиваются order by date desc, нумируются, берется только первая.
Wednesday, September 15th, 2010 08:57 pm (UTC)
в один проход
Wednesday, September 15th, 2010 09:44 pm (UTC)
Есть мысля - попробовать вместо второго селекта сделать group by как-нибудь
Wednesday, September 15th, 2010 08:05 pm (UTC)
SELECT a.userid, b.nickname
FROM
(
SELECT userid, MAX(date)
FROM foo
GROUP BY userid
) a
INNER JOIN foo b
ON a.userid = b.userid AND a.date = b.date
Wednesday, September 15th, 2010 08:29 pm (UTC)
и тем не менее, он тут есть :)
В целом работает, только к MAX(date) надо подписать AS date, иначе ругается на отсутсвие a.date
Wednesday, September 15th, 2010 09:46 pm (UTC)
Я имел в виду коррелирующие подзапросы, конечно. Предполагаю, что при тупом оптимизаторе, этот запрос будет гораздо быстрее выполнятся, чем классический вариант.
Wednesday, September 15th, 2010 08:50 pm (UTC)
не стандартно, зато 1 запрос:
select userid, LAST(nickname) from foo group by userid order by date
Wednesday, September 15th, 2010 09:58 pm (UTC)
это я наврал, конечно, нужно
select userid,last(nickname) from (select userid, nickname from foo order by date) group by userid
а это уже с подзапросом
Thursday, September 16th, 2010 01:21 pm (UTC)
А куда на работу берут с такими задачками? :) Если не секрет.
Thursday, September 16th, 2010 01:23 pm (UTC)
Ну вот ежели у нас будет очередная вакансия прикладного программиста со знанием БД, так я ее туда включу :)