2013-06-06 7 views
0

Мой мозг отказывается сотрудничать со мной сегодня, чтобы на самом деле подумать об этом правильно, поэтому я надеялся получить некоторую обратную связь: я хочу вернуть одну запись от каждого участника за их самый последний вход в система, но до сих пор я, очевидно, смог вернуть только одну запись для самого последнего дня и времени любого члена. Я знаю, что запрос не совсем правильно, но мой мозг отказывается действительно сотрудничать ...sql выберите последнее время для каждого члена

SQL-:

SELECT 
    cm.FNAME, 
    cm.LNAME, 
    cl.entry_access_point, 
    cl.date_entered, 
    cl.res_id, 
    dbo.HourMinuteSecond(cl.date_entered, getUTCDate())[Day:Hour:Minute:Second] 
FROM 
    cred.members cm, cred.allocate_log cl 
WHERE 
    cm.member_id = cl.member_id AND 
    cl.date_exited IS NULL AND 
    cl.evt_id = @eventId AND 
    date_entered IN (SELECT max(cl.date_entered) 
        FROM cred.allocate_log cl, cred.members cm 
        WHERE cl.member_id = cm.member_id) 
ORDER BY 
    cl.date_entered; 
+0

[Плохие привычки пинать : использование JOIN в старом стиле] (http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style-joins.aspx) - эта старая версия, стиль * список таблиц, разделенных запятыми * стиль был прекращен с ANSI - ** 92 ** SQL Standard (более ** 20 лет ** назад!) –

+0

Ну спасибо, но я просто пытаюсь чтобы повесить вещи. Я буду работать над своими способностями к объединению. – Jfabs

+0

Если вы только начинаете, изучите его с самого начала! Не начинайте привыкать к унаследованному стилю - используйте ** надлежащие ANSI JOINs ** всегда –

ответ

1

Просто добавьте правила для member_id в подзапрос:

SELECT 
cm.FNAME, 
cm.LNAME, 
cl.entry_access_point, 
cl.date_entered, 
cl.res_id, 
dbo.HourMinuteSecond(cl.date_entered, getUTCDate())[Day:Hour:Minute:Second] 
FROM cred.members cm, cred.allocate_log cl 
WHERE cm.member_id = cl.member_id AND 
    cl.date_exited IS NULL AND 
    cl.evt_id = @eventId AND 
    date_entered IN (
     SELECT max(cl.date_entered) 
     FROM cred.allocate_log cl, cred.members cms 
     WHERE cl.member_id = cms.member_id and cms.member_id = cm.member_id) 
ORDER BY cl.date_entered 

Но вы также должны заявление для evt_id в подзапроса, и это может быть упрощена, как это:

SELECT 
    cm.FNAME, 
    cm.LNAME, 
    cl.entry_access_point, 
    cl.date_entered, 
    cl.res_id, 
    dbo.HourMinuteSecond(cl.date_entered, getUTCDate())[Day:Hour:Minute:Second] 
    FROM cred.members cm, cred.allocate_log cl 
    WHERE cm.member_id = cl.member_id AND 
     cl.date_exited IS NULL AND 
     cl.evt_id = @eventId AND 
     date_entered >= ALL (
      SELECT cl.date_entered 
      FROM cred.allocate_log cls 
      WHERE cls.member_id = cm.member_id AND cls.evt_id = cl.evt_id) 
    ORDER BY cl.date_entered 

Изменение псевдонима для таблицы в подзапросе:

SELECT 
     cm.FNAME, 
     cm.LNAME, 
     cl.entry_access_point, 
     cl.date_entered, 
     cl.res_id, 
     dbo.HourMinuteSecond(cl.date_entered, getUTCDate())[Day:Hour:Minute:Second] 
     FROM cred.members cm, cred.allocate_log cl 
     WHERE cm.member_id = cl.member_id AND 
      cl.date_exited IS NULL AND 
      cl.evt_id = @eventId AND 
      date_entered >= ALL (
       SELECT cls.date_entered 
       FROM cred.allocate_log cls 
       WHERE cls.member_id = cm.member_id AND cls.evt_id = cl.evt_id) 
     ORDER BY cl.date_entered 
+0

Первый, который вы мне дали, работал отлично. Зачем мне нужен evt_id и в подзапросе? – Jfabs

+0

Ой, подождите, возможно, в случае, если member_id был найден в подзапросе, который не принадлежал evt_id в родительском запросе. Правильно? – Jfabs

+0

Да, я думаю, у вас есть много типов событий в журнале, но вы должны заинтересовать только один @eventId, правильно? – Mikhail

2

Лучший способ сделать этот вид запроса с использованием row_number(). Кроме того, вы должны научиться использовать синтаксис join вместо того, чтобы помещать объединения в предложение where.

select t.* 
from (SELECT cm.FNAME, cm.LNAME, cl.entry_access_point, cl.date_entered, cl.res_id, 
      dbo.HourMinuteSecond(cl.date_entered, getUTCDate()) as [Day:Hour:Minute:Second], 
      ROW_NUMBER() over (partition by cm.member_id order by cl.date_enetered desc) as seqnum 
     FROM cred.members cm join 
      cred.allocate_log cl 
      on cm.member_id = cl.member_id 
     WHERE cl.date_exited IS NULL AND 
      cl.evt_id = @eventId 
    ) t 
ORDER BY date_entered; 
+0

Хорошо, я не совсем уверен, что здесь происходит, но я пытаюсь разобраться, чтобы понять это лучше. Я сделал это против моего db, и он возвращает более одной записи для каждого члена FYI. Однако, спасибо. – Jfabs

+0

Изучив это немного, я собираюсь угадать, что вы намеревались использовать этот seqnum в какой-то момент, чтобы захватить самую последнюю, поэтому я был бы в безопасности, полагая, что нет способа вернуть только самые последние datetime, только способ его сортировки? – Jfabs

+0

Я бы принял это как свой ответ, но ответ Михаила дал мне именно то, что я искал. Независимо от того, +1 для вас, чтобы показать мне более «современный» путь к этому в отношении правильного объединения против того, что я сделал. Спасибо. – Jfabs

1
select 
    those fields 
from cred.members cm, 
join (
select member_id, max(date_entered) maxdate 
from cred.allocate_log 
where date_exited is null 
and evt_id = @eventId 
group by member_id 
) s on cm.member_id = s.member_id 
join cred.allocate_log cl on 
    cm.member_id = cl.member_id 
    and cl.date_entered = s.maxdate 

вы также можете использовать нестандартное CROSS APPLY оператор, который может сделать вещи проще, если там может быть больше, чем один ряд с заданной date_entered

select 
    those fields 
from cred.members cm 
cross apply (
    select top 1 
     fields from log 
    from cred.allocate_log cl 
    where cm.member_id = cl.member_id 
    and date_exited is null 
    and evt_id = @eventId 
    order by date_entered desc 
) 
+0

Я не закончил проверять это, но +1 для ответа, я всегда это ценю. – Jfabs