2013-08-16 8 views
5

Powiedzmy mam tabeli podobny do następującego:SELECT wiersze z drugą najwyższą wartość w kolumnie

Item   Description   Time 
-----  -----------   ----- 
ItemA1  descript    08-16-2013 00:00:00 
ItemA2  descript    08-16-2013 00:00:00 
ItemA3  descript    08-16-2013 00:00:00 
. 
. 
ItemAN  descript    08-16-2013 00:00:00 

ItemB1  descript    08-13-2013 00:00:00 
ItemB2  descript    08-13-2013 00:00:00 
ItemB3  descript    08-13-2013 00:00:00 
. 
. 
ItemBN  descript    08-13-2013 00:00:00 
. 
. 
. 
ItemX1  descript    01-13-2012 00:00:00 
ItemX2  descript    01-13-2012 00:00:00 
ItemX3  descript    01-13-2012 00:00:00 
. 
. 
ItemXN  descript    01-13-2012 00:00:00 

Grupy elementy są dodawane okresowo. Po dodaniu grupy przedmiotów wszystkie są dodawane w tym samym polu "Czas". "Czas" zasadniczo służy jako unikalny indeks dla tej grupy produktów.

Chcę WYBRAĆ grupę przedmiotów, które mają drugi najwyższy czas. W tym przykładzie moje zapytanie powinno wyciągnąć elementy "B". Wiem, że mogę zrobić max (time), aby WYBRAĆ elementy "A", ale nie wiem, jak zrobić drugie.

Moje kolumny "Czas" są przechowywane jako TIMESTAMP, jeśli oznacza to cokolwiek.

+0

Prawdopodobnie powinieneś przetestować zarówno rozwiązania MAX, jak i LIMIT/ORDER BY, ponieważ może wystąpić obniżenie wydajności w stosunku do LIMITów, w zależności od dostępności indeksów. http://stackoverflow.com/questions/426731/min-max-vs-order-by-and-limit –

+0

możliwy duplikat [Jakie jest najprostsze zapytanie SQL, aby znaleźć drugą największą wartość?] (http: // stackoverflow .pl/questions/32100/what-is-the-simplest-sql-query-to-find-the-second-largest-value) – heretolearn

Odpowiedz

13

Można spróbować czegoś takiego:

SELECT MAX(Time) 
FROM yourTable 
WHERE Time < (SELECT MAX(Time) FROM yourTable) 

SQLFiddle Demo

+0

Dlaczego upadły? – DarkAjax

+0

+1 za ładny przycisk fiddle sql, ale zapytanie nie zawiera elementów, ale po prostu czas –

+0

@DarkAjax, To rozwiązanie nie skaluje się wcale. Jak wybrałbyś wtedy 3 najwyższy poziom? Lub 4, 5, 6, n-ty? – Pacerier

7

Jedno podejście:

SELECT t.* 
FROM mytable t 
JOIN (SELECT l.time 
      FROM mytable l 
     GROUP BY l.time 
     ORDER BY l.time DESC 
     LIMIT 1,1 
    ) m 
    ON m.time = t.time 

ten wykorzystuje widok inline (przypisany alias m), aby powrócić drugi „największym " wartość czasu. GRUPA BY przedstawia nam odrębną listę, ORDER BY DESC umieszcza najnowszą jako pierwszą, a "sztuczką" jest LIMIT, który zwraca drugi wiersz. LIMIT (m, n) = (pomiń pierwsze m wiersze, powrót następnych n wierszy)

Przy tej wartości czasu możemy dołączyć do oryginalnej tabeli, aby uzyskać wszystkie wiersze z pasującą wartością czasu.


Wydajność zostanie poprawiona dzięki indeksowi z wiodącą kolumną time. (Myślę, że MySQL powinien być w stanie uniknąć operacji "Using filesort" i uzyskać dość szybko wynik z wbudowanego zapytania o widok.)

Ale, włączając predykat w zapytaniu do widoku śródliniowego, jeśli "wiesz", że drugi raz ostatni nigdy nie będzie więcej niż określoną liczbę dni, nie będzie bolało wydajność:

WHERE l.time > NOW() + INTERVAL -30 DAYS 

Ale z tym dodaje, że kwerenda nie zwróci „drugi” ostatnią grupę, czy to time jest ponad 30 dni temu.

Podejście do uzyskania drugiego najnowszego (podejście podane w innych odpowiedziach) może być szybsze, szczególnie jeśli nie ma indeksu z wiodącą kolumną z time, ale wydajność najlepiej będzie ocenić rzeczywistymi testami. Indeks z wiodącą kolumną czasu przyspieszy również podejście MAX().)

Podane przeze mnie zapytanie można łatwo rozszerzyć, aby uzyskać czwartą najnowszą, ostatnią wersję, itd., Zmieniając klauzulę LIMIT ... LIMIT(3,1), LIMIT(41,1) itd.

+0

+1 Najlepsza odpowiedź. –

+0

* UWAGA: * zapytanie w tej odpowiedzi używa specyficznej dla MySQL składni "LIMIT", która jest * nie * obsługiwana w większości (każdej) innej komercyjnej bazie danych. – spencer7593

+0

Składnia LIMIT w podzapytaniu nie jest obsługiwana w starszych wersjach MySQL. – Manu

1
SELECT T1.ITEM 
FROM YOURTABLE T1 
WHERE T1.TIME = (SELECT MAX(T2.TIME) 
        FROM YOURTABLE T2 
        WHERE T2.TIME < (SELECT MAX(T3.TIME) 
             FROM YOURTABLE T3 
            ) 
       ) 
0

Coś naprawdę proste jak to powinno działać

select * from my-table where time = 
    (Select top 1 time 
    from (select top 2 time from my-table order by time desc) 
    order by time asc) 
+0

'TOP' to składnia Microsoft SQL Server, nie obsługiwana przez MySQL. – spencer7593

+0

Dlatego należy korzystać z metody MAX() zgodnej z ANSI ... –

4

To powinno dać drugi największy czas:

SELECT time FROM table GROUP BY time ORDER BY time DESC LIMIT 1,1 
1

Get drugi, trzeci, czwarty ...... Pn najwyższa wartość przy użyciu następującego zapytania:

SELECT MIN(value) from yourTable WHERE value IN(SELECT TOP N value FROM yourTable ORDER BY value DESC) 

Zastąp N przez liczbę, tj. N = 2 dla drugiej najwyższej wartości, N = 3 dla trzeciej najwyższej wartości i tak dalej. Więc do użytku drugą najwyższą wartość:

SELECT MIN(value) from yourTable WHERE value IN(SELECT TOP 2 value FROM yourTable ORDER BY value DESC) 
0

Oto kolejne rozwiązanie, które myślę, że powinien pracować dla swojego problemu:

CREATE TEMPORARY TABLE xHighest AS (SELECT DISTINCT Time FROM `my-table` ORDER BY Time DESC LIMIT 1,1); 

SELECT * FROM `my-table` JOIN xHighest ON (my-table.Time = xHighest.Time); 

Można wybrać, czy drugi, trzeci ... Najwyższa wartość powinien użyj, zmieniając pierwszy parametr LIMIT.

0

mysql roztwór zasady granica

Przykład: dane 1, 2, 3, 4, 5.

LIMIT 2,1 oznacza, że ​​powrót 3. największą liczbę, z limitem 1,1 powrotu Drugi najwyższy numer i tak dalej:

SELECT rc. rc_officer_id FROM recovery_complain_officer rc ORDER BY rc. rc_officer_id DESC LIMIT 2,1

Powiązane problemy