Есть ли способ найти TOP X записей с сгруппированными данными? - PullRequest
1 голос
/ 02 июня 2010

Я работаю с сервером Sybase 12.5, и у меня есть таблица, определенная следующим образом:

CREATE TABLE SomeTable(
    [GroupID] [int] NOT NULL,
    [DateStamp] [datetime] NOT NULL,
    [SomeName] varchar(100),
    PRIMARY KEY CLUSTERED (GroupID,DateStamp)
)

Я хочу иметь возможность перечислять по [GroupID] только самые последние записи X по [DateStamp]. Кикер имеет X> 1, поэтому старый старый MAX () его не обрежет. Я предполагаю, что есть чудесный противный способ сделать это с помощью курсоров и чего-то еще, но мне интересно, есть ли более простой способ без этого.

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

Есть ли способ найти записи TOP X, но с группированными данными?

Ответы [ 2 ]

3 голосов
/ 02 июня 2010

Согласно интерактивному руководству, Sybase 12.5 поддерживает функции WINDOW и ROW_NUMBER(), хотя их синтаксис немного отличается от стандартного SQL.

Попробуйте что-то вроде этого:

SELECT SP.*
FROM (
    SELECT *, ROW_NUMBER() OVER (windowA ORDER BY [DateStamp] DESC) AS RowNum
    FROM SomeTable
    WINDOW windowA AS (PARTITION BY [GroupID])
) AS SP
WHERE SP.RowNum <= 3
ORDER BY RowNum DESC;

У меня нет экземпляра Sybase, поэтому я не проверял это. Я просто синтезирую этот пример из документа.


Я сделал ошибку. Документ, на который я смотрел, был Sybase SQL Anywhere 11. Кажется, что Sybase ASA вообще не поддерживает предложение WINDOW, даже в самой последней версии.

Вот еще один запрос, который может выполнить то же самое. Вы можете использовать самосоединение, чтобы сопоставить каждую строку SomeTable со всеми строками с одинаковым GroupID и более поздним DateStamp. Если более трех строк меньше, то у нас есть один из трех лучших.

SELECT s1.[GroupID], s1.[Foo], s1.[Bar], s1.[Baz]
FROM SomeTable s1
LEFT OUTER JOIN SomeTable s2
  ON s1.[GroupID] = s2.[GroupID] AND s1.[DateStamp] < s2.[DateStamp]
GROUP BY s1.[GroupID], s1.[Foo], s1.[Bar], s1.[Baz]
HAVING COUNT(*) < 3
ORDER BY s1.[DateStamp] DESC;

Обратите внимание, что вы должны перечислить те же столбцы в списке SELECT, что и в предложении GROUP BY. По сути, все столбцы из s1, которые вы хотите, чтобы этот запрос возвращал.

1 голос
/ 02 июня 2010

Вот довольно невероятный способ!

SELECT GroupID, DateStamp, SomeName
FROM SomeTable ST1
WHERE X < 
    (SELECT COUNT(*) 
     FROM SomeTable ST2 
     WHERE ST1.GroupID=ST2.GroupID AND ST2.DateStamp > ST1.DateStamp)

Редактировать Хотя решение Билла гораздо предпочтительнее.

...