Хитрый оператор SQL SELECT - PullRequest
2 голосов
/ 05 августа 2009

У меня проблема с производительностью при выборе данных в моем проекте.

Есть таблица с 3 столбцами: "id", "time" и "group"

  • Идентификаторы - это просто уникальные идентификаторы.
  • Время - дата создания записи.
  • Группа существует для объединения определенных записей.

Таким образом, данные таблицы могут выглядеть следующим образом:

ID | TIME      | GROUP
------------------------
1  | 20090805  | A
2  | 20090804  | A
3  | 20090804  | B
4  | 20090805  | B
5  | 20090803  | A
6  | 20090802  | B

... и т. Д.

Задача теперь состоит в том, чтобы выбрать «текущие» записи (их идентификаторы) в каждой группе на заданную дату. То есть для каждой группы найдите самую последнюю запись на данную дату.

Применяются следующие предварительные условия:

  • Я заранее не знаю разных групп - со временем может меняться много разных
  • Дата выбора может находиться «между» датами записей в таблице. Затем я должен найти ближайший в каждой группе. Таким образом, ВРЕМЯ меньше даты выбора, но максимум из тех, к которым применяется это правило в группе.

То, что я сейчас делаю, - это многошаговый процесс, который я хотел бы преобразовать в один оператор SELECT:

  1. SELECT DISTINCT group FROM table для поиска доступных групп
  2. Для каждой группы, найденной в 1), SELECT * FROM table WHERE time<selectionDate AND group=loop ORDER BY time DESC
  3. Возьмите первую строку каждого результата, найденного в 2)

Очевидно, что это не оптимально.

Так что я был бы очень рад, если бы более опытный эксперт по SQL мог бы помочь мне найти решение, позволяющее объединить эти шаги в одном выражении.

Спасибо!

Ответы [ 5 ]

10 голосов
/ 05 августа 2009

Следующее будет работать на SQL Server 2005+ и Oracle 9i +:

WITH groups AS (
       SELECT t.group,
              MAX(t.time) 'maxtime'
         FROM TABLE t
     GROUP BY t.group)
SELECT t.id,
       t.time,
       t.group
  FROM TABLE t
  JOIN groups g ON g.group = t.group AND g.maxtime = t.time

Любая база данных должна поддерживать:

SELECT t.id,
       t.time,
       t.group
  FROM TABLE t
  JOIN (SELECT t.group,
               MAX(t.time) 'maxtime'
          FROM TABLE t
      GROUP BY t.group) g ON g.group = t.group AND g.maxtime = t.time
5 голосов
/ 05 августа 2009

Вот как бы я это сделал в SQL Server:

SELECT * FROM table WHERE id in
(SELECT top 1 id FROM table WHERE time<selectionDate GROUP BY [group] ORDER BY [time])
1 голос
/ 05 августа 2009

Решение будет зависеть от сервера базы данных, поскольку синтаксис для запросов TOP различается. По сути, вы ищете запрос " top n на группу ", так что вы можете это сделать в Google, если хотите.

Вот решение в SQL Server. Следующее вернет 10 лучших игроков, которые бьют больше всего хоум-ранов в год с 1990 года. Ключ заключается в том, чтобы подсчитать «Ранж Home Run» каждого игрока за каждый год.

select 
  HRRanks.*
from
(
    Select 
      b.yearID, b.PlayerID, sum(b.Hr) as TotalHR,
      rank() over (partition by b.yearID order by sum(b.hr) desc) as HR_Rank
    from 
      Batting b
    where 
      b.yearID > 1990
    group by 
      b.yearID, b.playerID
) 
  HRRanks
where
  HRRanks.HR_Rank <= 10

Вот решение в Oracle (Лучшие продавцы на отдел)

SELECT deptno, avg_sal
FROM( 
      SELECT deptno, AVG(sal) avg_sal
      GROUP BY deptno
      ORDER BY AVG(sal) DESC
    )
WHERE ROWNUM <= 10;

Или используя аналитические функции:

SELECT deptno, avg_sal
FROM (
       SELECT deptno, avg_sal, RANK() OVER (ORDER BY sal DESC) rank
       FROM
       (
         SELECT deptno, AVG(sal) avg_sal
         FROM emp
         GROUP BY deptno
       )
     )
WHERE rank <= 10;

Или снова то же самое, но с использованием DENSE_RANK () вместо RANK ()

0 голосов
/ 04 мая 2015

ВЫБРАТЬ * ОТ TABB T1

QUALIFY ROW_NUMBER () OVER (PARTITION BY GROUPP, порядок TIMEE по id desc) = 1

0 голосов
/ 05 августа 2009
select * from TABLE where (GROUP, TIME) in (
    select GROUP, max(TIME) from things
        where TIME >= 20090804
        group by GROUP
    )

Протестировано с MySQL (но мне пришлось изменить имена таблиц и столбцов, потому что они являются ключевыми словами).

...