Запрос уникального значения на основе совокупности другого значения при полной группировке по третьему значению - PullRequest
2 голосов
/ 21 января 2010

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

Скажем, у меня есть гипотетическая таблица 'X', которая выглядит следующим образом:

GroupID ID (identity)   SomeDateTime
--------------------------------------------
1       1000        1/1/01
1       1001        2/2/02
1       1002        3/3/03
2       1003        4/4/04
2       1004        5/5/05

Я хочу сделать запрос, чтобы результирующий набор выглядел так:

----------------------------------------
1       1002        3/3/03
2       1004        5/5/05

В основном я хочу получить значение MAX SomeDateTime, сгруппированное по моему столбцу GroupID. Кикер в том, что я не хочу группировать по столбцу ID, Я просто хочу знать «ID», который соответствует MAX SomeDateTime.

Я знаю, что одно псевдо-решение будет:

;WITH X1 as (
    SELECT MAX(SomeDateTime) as SomeDateTime, GroupID 
    FROM X
    GROUP BY GroupID
)
SELECT X1.SomeDateTime, X1.GroupID, X2.ID
FROM X1
    INNER JOIN X as X2
        ON X.DateTime = X2.DateTime

Но это не решает тот факт, что DateTime может быть не уникальным. И кажется, что присоединение к DateTime кажется таким неряшливым.

Другое псевдо-решение может быть:

SELECT X.GroupID, MAX(X.ID) as ID, MAX(X.SomeDateTime) as SomeDateTime
FROM X
GROUP BY X.GroupID

Но нет никаких гарантий, что ID действительно будет соответствовать строке, из которой SomeDateTime происходит.

Третий менее полезный параметр может быть:

SELECT TOP 1 X.GroupID, X.ID, X.SomeDateTime
FROM X
WHERE X.GroupID = 1
ORDER BY X.SomeDateTime DESC

Но очевидно, что это работает только с одним известным GroupID. Я хочу иметь возможность присоединиться к этому набору результатов GroupID и / или ID.

Кто-нибудь знает какие-нибудь умные решения? Любое хорошее использование оконных функций?

Спасибо!

Ответы [ 3 ]

1 голос
/ 21 января 2010

Ваше первое решение правильное. Я бы написал, как внутренний выбор (заметьте, синтаксис в innnersleect зависит от dbms, и я привык к db2 в эти дни, вот что вы получаете: -):

Выберите g.groupid, g.id, g.somedatetime

из x g, (выберите s.groupid, max (s.somedatetime) из x s group по s.groupid) si

где g.groupid = s.groupid и g.somedatetime = si.somedatetime;

Но, как вы заметили, если somedatetime не является уникальным для идентификатора, вы получите несколько строк для каждого такого идентификатора группы. чтобы устранить это, вам понадобится дополнительный суб-выбор, чтобы получить max (id) для max (somedatetime). Очень грязно:

Выберите g.groupid, g.id, g.somedatetime

из x g, (выберите s.groupid, max (s.somedatetime) как maxdate из группы x s по s.groupid) si,

(выберите i.groupid, max (i.id) как maxid, i.somedatetime из xi, где i.groupid = si.groupid и i.somedatetime = si.maxdate group, для i.groupid, i.somedatetime) si2

где g.groupid = s.groupid и g.id = maxid и g.somedatetime = maxdate;

1 голос
/ 21 января 2010

Я думаю, что это будет делать то, что вы хотите.

;WITH X1 
AS 
(
    SELECT SomeDateTime
           ,GroupID 
           ,ID
           ,ROW_NUMBER() OVER (PARTITION BY GroupID
                               ORDER BY SomeDateTime DESC
                               ) AS rn
    FROM X
)
SELECT SomeDateTime
       ,GroupID
       ,ID
FROM X1
WHERE rn = 1
0 голосов
/ 07 апреля 2010

Для решения этой проблемы вы также можете использовать комбинацию функции перекрестного наложения и верхней части (1)

select
 distinct(GroupId)
 ,maxvales.SomeDateTime
from
 X as outerX
 cross apply
  (select top(1) SomeDateTime from X as innerX where innerX.GroupID = outerX.GroupID order by SomeDateTime desc) as maxvales
...