2011-12-08 3 views
3

Учитывая таблицу с несколькими строками поля int и тем же идентификатором, можно ли вернуть 2-е максимальное и второе минимальное значение из таблицы.Второе максимальное и минимальное значения

Таблица состоит из

ID  | number 
------------------------ 
1  |  10 
1  |  11 
1  |  13 
1  |  14 
1  |  15 
1  |  16 

Окончательный результат будет

ID  | nMin | nMax 
-------------------------------- 
1  |  11 | 15 
+0

какая версия SQL? Много способов ... –

+0

2008. дешевле лучше ... 100s из миллионов строк –

+1

что должно быть результатом, если вставлены 2 | 17 и 2 | 12 строк? – danihp

ответ

6

Вы можете использовать row_number, чтобы присвоить рейтинг по ID. Затем вы можете group by id и выбрать строки с ранжированием, которым вы пользуетесь. Следующий пример выбирает второй низкий и третий высокий:

select id 
,  max(case when rnAsc = 2 then number end) as SecondLowest 
,  max(case when rnDesc = 3 then number end) as ThirdHighest 
from (
     select ID 
     ,  row_number() over (partition by ID order by number) as rnAsc 
     ,  row_number() over (partition by ID order by number desc) as rnDesc 
     ) as SubQueryAlias 
group by 
     id 

max просто, чтобы выбрать одну ненулевое значение; вы можете заменить его min или даже avg, и это не повлияет на результат.

+0

+1 Я не могу поверить, что только 1 из 5 ответов на самом деле справлялись с этим ... и также допускали разные идентификаторы. – gbn

+0

, чтобы получить второй максимум, почему бы просто не выбрать X.* from (выберите row_number() над разделом по порядку id по номеру) как rn, id, number) X где rn = 2'? (И затем, чтобы получить второй самый низкий, добавьте «desc» на заказ? –

+0

@MakeMinePanacea: OP запрашивает обе в одной строке, поэтому ответ должен «развернуть» две конкретные строки на два столбца. – Andomar

-1

Как я сам узнал только сегодня решение заключается в использовании LIMIT. Вы заказываете результаты так, чтобы наивысшие значения находились сверху и ограничивали результат до 2. Затем вы выбираете этот подзапрос и заказываете его наоборот и принимаете только первый.

SELECT somefield FROM (
SELECT somefield from table 
ORDER BY somefield DESC LIMIT 2) 
ORDER BY somefield ASC LIMIT 1 
+0

Вопрос идет о MSSQL 2K8, который не имеет 'LIMIT'. – Yuck

+0

@Yuck О, комментарий был добавлен после того, как я начал писать. Дерьмо. –

1

Это будет работать, но увидеть предостережения:

SELECT Id, number 
INTO #T 
FROM (
    SELECT 1 ID, 10 number 
    UNION 
    SELECT 1 ID, 10 number 
    UNION 
    SELECT 1 ID, 11 number 
    UNION 
    SELECT 1 ID, 13 number 
    UNION 
    SELECT 1 ID, 14 number 
    UNION 
    SELECT 1 ID, 15 number 
    UNION 
    SELECT 1 ID, 16 number 
) U; 

WITH EX AS (
    SELECT Id, MIN(number) MinNumber, MAX(number) MaxNumber 
    FROM #T 
    GROUP BY Id 
) 
SELECT #T.Id, MIN(number) nMin, MAX(number) nMax 
FROM #T INNER JOIN 
    EX ON #T.Id = EX.Id 
WHERE #T.number <> MinNumber AND #T.number <> MaxNumber 
GROUP BY #T.Id 

DROP TABLE #T; 

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

+0

lordy, что сложно – gbn

+0

@gbn: Один запрос для поиска MIN/MAX, второй для * not * использовать их :) Дерьмо в верхней части просто tup, поэтому его можно запустить с помощью copy & paste, но я уверен, что вы это знаете. – Yuck

+0

Мое намерение состояло в том, чтобы подчеркнуть, что самосоединения и агрегаты являются излишними по сравнению с использованием ROW_NUMBER (или DENSE_RANK для совместного 2-го максимума и т. Д.), Делает это намного элегантнее. – gbn

0

Это был бы лучший способ. Я быстро собрал это вместе, но если вы можете объединить два запроса, вы получите именно то, что искали.

select * 
from 
(
    select 
     myID, 
     myNumber, 
     row_number() over (order by myID) as myRowNumber 
    from MyTable 
) x 
where x.myRowNumber = 2 

select * 
from 
(
    select 
     myID, 
     myNumber, 
     row_number() over (order by myID desc) as myRowNumber 
    from MyTable 
) y 
where x.myRowNumber = 2 
1

Вы можете выбрать следующий минимальное значение, используя следующий метод:

SELECT MAX(Number) 
FROM 
(
    SELECT top 2 (Number) 
    FROM table1 t1 
    WHERE ID = {MyNumber} 
    order by Number 
)a 

Это работает только если вы можете ограничить внутренний запрос с, где положение

0

пусть имя таблицы будет tblName. выберите max (number) из tblName, где число не включено (выберите max (число) из tblName);

То же самое для мин, просто замените max на мин.

Смежные вопросы