SQL-запрос на максимальную дату - PullRequest
2 голосов
/ 13 марта 2011

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

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

Таблица записей (Entry):

  UserID   | EntryDate  
 ----------------------
    1      |  5/4/2010  
    1      |  4/4/2010  
    1      |  3/4/2010  
    1      |  2/4/2010  
    2      |  5/4/2010
    2      |  4/4/2010

Таблица состояния записи (Status):

  UserID   | StatusDate  | Detail
  -------------------------------
    1      |  5/28/2010  |  D-1
    1      |  4/24/2010  |  D-2
    1      |  4/5/2010   |  D-3
    1      |  2/28/2010  |  D-4

Ожидаемый результат:

UserID | EntryDate | Detail
---------------------------
  1    | 5/4/2010  |  D-2
  1    | 4/4/2010  |  D-4
  1    | 3/4/2010  |  D-4
  1    | 2/4/2010  | <NULL>

В моем предыдущем вопросе вы можете увидеть мои усилия и связанные с ними ответы, но я сузил проблему, чтобы упростить проблему.

Я пытался сделать что-то подобное (но я знаю, что я должен быть ужасно выключен):

         SELECT E.EntryDate, 
                S.Detail, 
                MAX(S.StatusDate) AS MaxStatusDate
           FROM Entry AS E 
LEFT OUTER JOIN Status AS S ON E.EntryDate >= S.StatusDate

Ответы [ 4 ]

3 голосов
/ 13 марта 2011

Я думаю, вам нужно что-то вроде

SELECT E.UserID
    , E.EntryDate
    , (SELECT TOP 1 Detail
       FROM Status AS S
       WHERE S.UserID = E.UserID
       AND S.StatusDate <= E.EntryDate
       ORDER BY S.StatusDate DESC)
FROM Entry AS E

Если ваша база данных не поддерживает TOP или по причинам производительности вы бы предпочли избегать ORDER BY, вы можете попробовать что-то вроде:

SELECT E.UserID
    , E.EntryDate
    , (SELECT S1.Detail
       FROM Status AS S1
       WHERE S1.UserID = E.UserID
       AND S1.StatusDate = (SELECT MAX(S2.StatusDate)
                            FROM Status AS S2
                            WHERE S2.UserID = E.UserID
                            AND S2.StatusDate <= E.EntryDate))
FROM Entry AS E
1 голос
/ 14 марта 2011
SELECT
  e.UserID,
  e.EntryDate,
  s.Detail
FROM Entry e
  INNER JOIN (SELECT DISTINCT UserID FROM Status) u
    ON e.UserID = u.UserID
  LEFT JOIN (
    SELECT
      e.UserID,
      e.EntryDate,
      MAX(s.StatusDate) AS StatusDate
    FROM Entry e
      INNER JOIN Status s
        ON e.UserID = s.UserID AND e.EntryDate >= s.StatusDate
    GROUP BY e.UserID, e.EntryDate
  ) sd
    ON e.UserID = sd.UserID AND e.EntryDate = sd.EntryDate
  LEFT JOIN Status s
    ON sd.UserID = s.UserID AND sd.StatusDate = s.StatusDate

Список отдельных пользователей используется для фильтрации тех пользователей в Entry, которые не представлены в Status.

Затем полученный набор объединяется с производной таблицей, которая содержит максимумзначения даты состояния, соответствующие датам ввода.

Наконец, таблица Status снова соединяется, на этот раз для получения подробной информации.

Последние два объединения являются оставленными соединениями, поэтомуНабор результатов будет содержать все строки из Entry для каждого пользователя, найденного в Status, а внутреннее объединение гарантирует, что для всех остальных не будет ни одного.

1 голос
/ 13 марта 2011

Способ row_number для баз данных, которые его поддерживают:

SELECT  *
FROM    (
        SELECT  ROW_NUMBER() OVER (
                    PARTITION BY e.UserId, e.EntryDate
                    ORDER BY s.StatusDate desc) as rn
        ,       *
        FROM    Entry e
        INNER JOIN    
                Status s
        ON      s.UserID = e.UserID
                AND s.StatusDate <= e.EntryDate
        ) as SubQueryAlias
where   rn = 1
1 голос
/ 13 марта 2011

Я не думаю, что есть универсальный способ сделать это, но на некоторых диалектах SQL вы можете использовать TOP или LIMIT в подзапросе, чтобы получить значение из столбца в первой соответствующей записи на основе сортировки (ORDER BY) в другом столбце.

Например ...

SELECT
  Entry.*,
  ( SELECT TOP 1 
      Status.Detail
    FROM Status
    WHERE
      Entry.UserID = Status.UserID AND
      Entry.EntryDate >= Status.StatusDate
    ORDER BY
      Entry.EntryDate
  ) As StatusDetail
...