t-sql Aggregate Max - PullRequest
       30

t-sql Aggregate Max

0 голосов
/ 02 сентября 2010

У меня есть таблица: CREATE TABLE [dbo]. [Test] ( [имя] nvarchar (max) NULL, [date] datetime NULL )

И записи на нем:

a 2010-09-02 12:00:00 
a 2010-09-02 11:00:00 
b 2010-09-02 12:00:00 
b 2010-09-02 11:00:00

И я хочу получить все имя с самой новой датой:

Я могу сделать:

select t.[name] from test t
group by t.[name]
having max(date) = (select MAX(DATE) from test where [name] = t.[name])

у которых есть одна проблема - я не могу получить дату

Я могу сделать:

select t.* 
    from test t
    where t.[date] = (select MAX(DATE) from test where [name] = t.[name])

без проблем

Мой вопрос: Могу ли я сделать это лучше? Я получу около 10 000 записей из таблицы добавочных таблиц (каждый день еще 10 000 результатов).

Привет

Ответы [ 2 ]

2 голосов
/ 02 сентября 2010

Какая версия SQL Server?

SQL 2005 и выше:

SELECT *
FROM
   (SELECT Item = Row_Number() OVER (PARTITION BY [name] ORDER BY [date] DESC), * FROM test) X
WHERE Item = 1

SQL 2000:

SELECT T.*
FROM
   test T
   INNER JOIN (
      SELECT [name], MaxDt = Max([date]) FROM test GROUP BY [name]
   ) X ON T.[name] = X.[name] AND T.[date] = X.MaxDt

Если у вас могут быть повторяющиеся даты, тогда для версии SQL 2000 потребуется еще один шаг, чтобы свести ее к одной строке.

@ Одед указал, что вы можете просто получить максимальную дату. Если все, что вам нужно, это имя и дата, тогда его запрос лучше. Но если мое подозрение верно, что вам нужно больше элементов из той же строки, тогда вам понадобятся такие запросы.

Вот еще одна версия SQL 2005:

SELECT
   T.*
FROM
   test T
   CROSS APPLY (
      SELECT TOP 1 [date]
      FROM test T2
      WHERE T.[name] = T2.[name]
      ORDER BY T2.[date] DESC
   ) X
WHERE
   T.[date] = X.[date]

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

Обновление

Теперь, когда я знаю, что это SQL 2008:

Решение row_number () является самым простым и простым. Я бы начал с этого. Если производительности недостаточно, и таблица является дочерней по отношению к родительской таблице, у которой каждое [имя] есть только один раз, попробуйте решение CROSS APPLY с внешней таблицей (тест T) в качестве родительской:

SELECT
   X.*
FROM
   Parent P
   CROSS APPLY (
      SELECT TOP 1 *
      FROM test T
      WHERE P.[name] = T.[name]
      ORDER BY T.[date] DESC
   ) X

Если родительской таблицы нет, вы можете попробовать вышеуказанные запросы или использовать SELECT DISTINCT [name] FROM test, но я не уверен, что это улучшит производительность:

SELECT
   X.*
FROM
   (SELECT DISTINCT [name] FROM test) P
   CROSS APPLY (
      SELECT TOP 1 *
      FROM test T
      WHERE P.[name] = T.[name]
      ORDER BY T.[date] DESC
   ) X
2 голосов
/ 02 сентября 2010

При этом будут выбраны разные имена и самая новая дата, связанная с каждым:

select t.[name], MAX(t.[date]) 
from test t
group by t.[name]

При использовании GROUP BY вы также можете использовать агрегатные функции в предложении SELECT для столбцов, которые не являются частьюгруппировка.

Из MSDN ( Агрегатные функции ):

Агрегатные функции часто используются с предложением GROUP BY инструкции SELECT.

...