Как использовать Partition By или Max?

У меня есть следующая таблица (my_data):

year |  X  |  Y
-----+-----+-----
2010 |  A  |  10
2011 |  A  |  20
2011 |  B  |  99
2009 |  C  |  30
2010 |  C  |  40


каков наилучший / наименьший оператор SQL для извлечения только данных, относящихся к наивысшему году и сгруппированных по 'X', например:

year |  X  |  Y
-----+-----+-----
2011 |  A  |  20
2011 |  B  |  99
2010 |  C  |  40


Обратите внимание, что эта таблица результатов будет использоваться в объединении.


person Stef Heyenrath    schedule 01.06.2011    source источник
comment
Почему 2009 не их результат ?????   -  person Algorithmist    schedule 01.06.2011
comment
Я забыл включить информацию о том, что данные должны быть сгруппированы по столбцу «X».   -  person Stef Heyenrath    schedule 01.06.2011


Ответы (11)


Вы также можете быть переносимым и использовать ВНЕШНЕЕ СОЕДИНЕНИЕ:

select t1.year, t1.x, t1.y
  from my_data t1
  left join my_data t2
    on t2.x = t1.x
   and t2.year > t1.year
 where t2.x is null
person Benoit    schedule 01.06.2011

Это намного проще, чем другие решения:

SELECT x, max(year), MAX(y) KEEP (DENSE_RANK FIRST ORDER BY year DESC)
  FROM table
  GROUP BY x
person Gary Myers    schedule 01.06.2011

Вы можете использовать общее табличное выражение (CTE), работает также с повторяющимися строками (при необходимости). План выполнения такой же, более или менее

;With my_data_cte as (
    SELECT [year], x,y,ROW_NUMBER() OVER (
        PARTITION BY x
        ORDER BY [year] desc) as rn
FROM [dbo].[my_data])
select [year], x,y from my_data_cte 
where rn = 1
person Artyom    schedule 08.07.2015

Гэри Майерс, ваше решение не работает, если, например, для значения A год меньше 2010 года и этот год имеет максимальное значение. (Например, если существует строка 2005, A, 50) Чтобы получить правильное решение, используйте следующее. (который просто меняет местами значения)

SELECT x, max(y), MAX(year) KEEP (DENSE_RANK FIRST ORDER BY y DESC)
FROM test
GROUP BY x
person AleksandarT    schedule 22.09.2014

Вы можете выбрать самый последний год для каждого X, используя подзапрос в ваших критериях:

select a.year, a.x, a.y
from my_data a
where
  a.year = (
    select max(a_yr.year) from my_data a_yr
    where a_yr.x = a.x);

Данные:

year |  X  |  Y
-----+-----+-----
2010 |  A  |  10
2011 |  A  |  20
2011 |  B  |  99
2009 |  C  |  30
2010 |  C  |  40

Результаты:

year |  X  |  Y  
-----+-----+-----
2011 |  A  |  20 
2011 |  B  |  99 
2010 |  C  |  40 

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

person Stevoisiak    schedule 09.12.2020

это тоже может быть решением

выберите наибольшую ((e), (g), (c), (a), (b)) как самую последнюю дату от abc

person Amardeep Bhagat    schedule 02.08.2017
comment
Благодарим вас за этот фрагмент кода, который может оказать немедленную помощь. Правильное объяснение значительно повысило бы его образовательную ценность, показав почему это хорошее решение проблемы, и сделает его более полезным для будущих читателей с похожими, но не идентичными вопросами. Пожалуйста, отредактируйте свой ответ, чтобы добавить пояснения и указать, какие ограничения и допущения применяются. - person Toby Speight; 02.08.2017

Самый простой - это

Select * 
from table 
where year = (select max(year) from table)

Это может вызвать сканирование таблицы, если нет индекса за год. Но с индексом должна быть работоспособна

person Karl    schedule 01.06.2011
comment
Но это не вернет значение для «C» и 2010, как того требует OP. - person Frank Schmitt; 01.06.2011
comment
Это не даст желаемого результата - person Lukas Eder; 01.06.2011

person    schedule
comment
Да, это довольно элегантный способ сделать это - person Lukas Eder; 01.06.2011
comment
stackoverflow.com/questions/2854257/ - person zloctb; 11.10.2015

person    schedule
comment
Спасибо за этот ответ, все работает правильно. Однако я принял «сюрик» в качестве ответа, потому что его немного легче понять. - person Stef Heyenrath; 01.06.2011

person    schedule
comment
@Nikolay Похоже, вы добавили подсветку к исходному коду. правильно? Спасибо - person minglotus; 17.06.2015

person    schedule
comment
Почему LEFT JOIN, а не INNER JOIN? Почему WHERE 1=1? Также использование соединения менее эффективно, чем использование MAX(...) KEEP( DENSE_RANK ... ). - person MT0; 23.07.2015
comment
txn для исправления = ›исправлено для внутреннего соединения + добавлено место для удобства пользователя для разработчиков ... - person Yordan Georgiev; 23.07.2015