Подзапрос, чтобы вернуть последнюю запись для каждого родительского идентификатора

StackOverflow https://stackoverflow.com/questions/625055

  •  05-07-2019
  •  | 
  •  

Вопрос

У меня есть родительская таблица с записями для документов, и у меня есть таблица истории, которая регистрирует запись аудита каждый раз, когда пользователь обращается к одному из документов.

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

Таким образом, для


    DOCUMENTS
    ID | NAME
    1  | Document 1
    2  | Document 2
    3  | Document 3
    4  | Document 4
    5  | Document 5

    HISTORY
    DOC_ID | USER_ID | TIMESTAMP
    1      | 12345   | TODAY
    1      | 11111   | IN THE PAST
    1      | 11111   | IN THE PAST
    1      | 12345   | IN THE PAST
    2      | 11111   | TODAY
    2      | 12345   | IN THE PAST
    3      | 12345   | IN THE PAST

Я бы хотел получить ответ от моего поиска, например


    ID | NAME       | LAST_USER_ID
    1  | Document 1 | 12345
    2  | Document 2 | 11111
    3  | Document 3 | 12345
    4  | Document 4 | 
    5  | Document 5 | 

Могу ли я легко сделать это с помощью одного SQL-запроса и объединения двух таблиц?

Это было полезно?

Решение

Пересмотр произведений Энди Уайта и замена квадратных скобок (нотация MS SQL Server) на DB2 (и SQL стандарта ISO) «идентификаторы с разделителями»:

SELECT d.id, d.name, h.last_user_id
    FROM Documents d LEFT JOIN
         (SELECT r.doc_id AS id, user_id AS last_user_id
              FROM History r JOIN
                   (SELECT doc_id, MAX("timestamp") AS "timestamp"
                        FROM History
                        GROUP BY doc_id
                   ) AS l
                   ON  r."timestamp" = l."timestamp"
                   AND r.doc_id      = l.doc_id
         ) AS h
         ON d.id = h.id

Я не совсем уверен, является ли " временная метка " или "TIMESTAMP" правильно - вероятно, последнее.

Преимущество этого состоит в том, что он заменяет внутренний коррелированный подзапрос в версии Энди более простым некоррелированным подзапросом, который потенциально может быть (радикально?) более эффективным.

Другие советы

Я не смог получить " HAVING MAX (TIMESTAMP) " для запуска в SQL Server - я полагаю, что требуется логическое выражение, такое как "max (TIMESTAMP)" > 2009-03-05 & Quot; или что-то, что не применимо в этом случае. (Возможно, я что-то не так делаю ...)

Вот кое-что, что, кажется, работает - обратите внимание, что объединение имеет 2 условия (не уверен, хорошо это или нет):

select
    d.ID,
    d.NAME,
    h."USER_ID" as "LAST_USER_ID"
from Documents d
left join History h
    on d.ID = h.DOC_ID
    and h."TIMESTAMP" =
    (
        select max("TIMESTAMP")
        from "HISTORY"
        where "DOC_ID" = d.ID
    )

Это не использует объединение, но для некоторых запросов, подобных этому, я хотел бы встроить выбор для поля. Если вы хотите уловить ситуацию, когда ни один пользователь не получил доступ, вы можете обернуть его с помощью NVL ().

select a.ID, a.NAME,
(select x.user_id
 from HISTORY x
 where x.doc_id = a.id
   and x.timestamp = (select max(x1.timestamp)
                      from HISTORY x1
                      where x1.doc_id = x.doc_id)) as LAST_USER_ID
from DOCUMENTS a
where <your criteria here>

Я думаю, что это должно быть примерно так:

SELECT ID, Name,  b.USER_ID as LAST_USER_ID
FROM DOCUMENTS a LEFT JOIN
    ( SELECT DOC_ID, USER_ID 
          FROM HISTORY
              GROUP BY DOC_ID, USER_ID
              HAVING MAX( TIMESTAMP )) as b
    ON a.ID = b.DOC_ID

это также может работать:

SELECT ID, Name,  b.USER_ID as LAST_USER_ID
FROM DOCUMENTS a 
  LEFT JOIN HISTORY b ON a.ID = b.DOC_ID
GROUP BY DOC_ID, USER_ID
HAVING MAX( TIMESTAMP )
Select ID, Name, User_ID
From Documents Left Outer Join
History a on ID = DOC_ID
Where ( TimeStamp = ( Select Max(TimeStamp)
                      From History b
                      Where a.DOC_ID = b.DOC_ID ) OR
        TimeStamp Is NULL )  /* this accomodates the Left */
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top