SQL: Как сделать запрос на соединение, имея только «самую большую» запись любого «типа»? - PullRequest
2 голосов
/ 02 февраля 2012

У меня есть две таблицы: типы событий таблицы и события таблицы с отношением один-ко-многим.Каждое событие имеет метку времени.Теперь я хотел бы получить SQL-запрос, который возвращает мне каждый тип события + соответствующее ему событие с последней отметкой времени (которая в этом случае может быть уникальной).

Я не совсем уверен, как это происходитПредполагается, что это будет сделано с SQL напрямую правильным способом.До сих пор я использовал что-то вроде этого:

select * from eventtypes left join 
(
    select events.* from events right join 
    (
        select max(timestamp) as maxtimestamp from events groupby eventtypeid
    ) maxtimestamps
    on events.timestamp = maxtimestamps.maxtimestamp
) lastevents
on eventtypes.id = lastevents.eventtypeid

(Простите за *. Это не производство, я просто написал это из своей головы) Эти два внутренних выбора всегда заставляли меня задуматься, неправильный путь.Я всегда думал, что должно быть что-то вроде этого:

select max(timestamp), corresponding(id), corresponding(name), ... 
from events groupby eventtypeid

Я думаю, что функции, подобной соответствующей (), не существует.Зачем?Разве это не может быть реализовано быстрее на сервере sql, чем выполнение 2 select и соединение?Или есть другой способ сделать это эффективно в SQL?Или это уже эффективно?

Ответы [ 2 ]

3 голосов
/ 02 февраля 2012

Поскольку метка времени гарантированно будет уникальной (и только если это правда), этот запрос будет делать:

select 
      eventtypes.*,
      events.*
from 
    events A INNER JOIN eventtypes B ON A.eventtypeid=b.id
WHERE 
    A.timestamp IN (SELECT MAX(timestamp) FROM events GROUP BY eventtypeid)
2 голосов
/ 02 февраля 2012

Ваш запрос может быть упрощен до:

select 
      eventtypes.*,
      events.*
from 
    eventtypes 
  left join 
      events 
    join 
      (
          select
                eventtypeid,                             --- this line added 
                max(timestamp) as maxtimestamp 
          from events 
          group by eventtypeid
      ) maxtimestamps
    on  events.timestamp = maxtimestamps.maxtimestamp
    AND events.eventtypeid = maxtimestamps.eventtypeid   --- and this
  on eventtypes.id = lastevents.eventtypeid

Строки были добавлены, потому что ваша версия может показывать неверные результаты, если timestamp не является уникальным.


Во многих СУБД есть функции, называемые «аналитическими» или «оконными», которые могут дать вам те же результаты, как вы описываете:

SELECT
      et.*,
      e.*
FROM eventtypes et
  LEFT JOIN
    ( SELECT 
            events.*,
            ROW_NUMBER() OVER(PARTITION BY eventtypeid 
                              ORDER BY timestamp DESC )
              AS RowNum
      FROM events
    ) e
    ON e.eventtypeid = et.eventtypeid
    AND e.RowNum = 1
...