SQL Server WYBIERZ OSTATNIE N wierszy

139

To znane pytanie, ale najlepszym rozwiązaniem, jakie znalazłem, jest coś takiego:

SELECT TOP N *
FROM MyTable
ORDER BY Id DESC

Mam tabelę z wieloma rzędami. Nie można użyć tego zapytania, ponieważ zajmuje dużo czasu. Jak więc mogę wybrać ostatnie N wierszy bez użycia ORDER BY?

EDYTOWAĆ

Przepraszamy, powtórzone pytanie tego

Diego
źródło
Co oznacza „ostatnie N”? Bez zamówienia „ostatnie N” nie ma większego sensu. Jeśli masz na myśli „ostatnie N do wstawienia”, nie możesz polegać na SQL Server, który Ci to zapewni - musisz użyć klauzuli ORDER BY.
Daniel Renshaw
@Daniel Renshaw: Ostatnie N tabeli bez wymuszania przez SQL Server zamawiania wszystkich tabel, ponieważ robi się bardzo wolno
Diego
Zapytanie w Twoim pytaniu jest najlepszym sposobem. Jeśli idjest indeksowany, po prostu przeskanuje ten indeks w odwrotnej kolejności i zatrzyma się po pierwszych 5 wierszach. Jeśli nie jest indeksowany, będzie musiał wykonać TOP Nsortowanie. Nie będzie to gorsze niż jakikolwiek inny sposób. Nie sortuje całego stołu (chociaż musiałby przeskanować cały stół)
Martin Smith

Odpowiedzi:

38

Możesz to zrobić również za pomocą funkcji NUMER WIERSZA WEDŁUG PARTYCJI. Świetny przykład można znaleźć tutaj :

Używam tabeli Zamówienia w bazie danych Northwind ... Teraz pobierzmy ostatnie 5 zamówień złożonych przez pracownika 5:

SELECT ORDERID, CUSTOMERID, OrderDate
FROM
(
    SELECT ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY OrderDate DESC) AS OrderedDate,*
    FROM Orders
) as ordlist

WHERE ordlist.EmployeeID = 5
AND ordlist.OrderedDate <= 5
JonVD
źródło
1
Funkcja NUMER WIERSZA WEDŁUG PARTYCJI również korzysta z sortowania ... musisz posortować tabelę, aby przypisać numery wierszy dla każdego rekordu ...
Sadhir
To prawda, ale bez jakiegoś rodzaju natury to po prostu nie zadziała, najlepszym rozwiązaniem jest zindeksowanie głównych trafionych kolumn i uruchomienie czegoś podobnego do powyższego zapytania.
JonVD
101

Możesz ustawić serwer SQL tak, aby wybierał ostatnie N wierszy za pomocą tego kodu SQL:

select * from tbl_name order by id desc limit N;
Niru Mukund Shah
źródło
2
A co z kompatybilnością wersji?
Fractaliste
63
To nie działa w SQL Server. Wygląda na funkcję MySQL, PostgreSQL i SQLite.
Tim Friesen
3
Wszystkie wymienione produkty są definitywnie serwerami SQL. Jeśli chcesz porozmawiać o serwerze MS SQL, dlaczego nie nazwać go tak?
gena2x
4
Jestem zdezorientowany, pytanie dotyczy tego, jak utworzyć zapytanie wybierające „bez użycia ORDER BY”, a zapytanie wybierające w Twojej odpowiedzi ma „order by”. Czy to jest rodzaj „zamówienia według” bez „zamówienia według”?
Robert Sinclair,
5
@ gena2x to pytanie jest oznaczone jako SQL Server. Ten tag odnosi się do Microsoft SQL Server.
Martin Smith
51

Przetestowałem kod JonVD, ale okazało się, że był bardzo wolny, 6s.

Ten kod zajął 0s.

SELECT TOP(5) ORDERID, CUSTOMERID, OrderDate    
FROM Orders where EmployeeID=5    
Order By OrderDate DESC
ABI
źródło
4
Ile rzędów ?? Kiedy masz dużo wierszy, które mogą być NAPRAWDĘ powolne
Diego
@Diego Dlaczego tak jest? Jeśli masz OrderDatezaindeksowane, zasadniczo równie szybkie powinno być wybranie pierwszego lub ostatniego N wierszy zapytania. Zdaję sobie sprawę, że istnieje szansa OrderDate, że wstawione zamówienie dobrze koreluje, ale jest to w najlepszym przypadku efekt uboczny i nadal wymaga skanowania tabeli, prawda? (I nie sądzę, żeby to odpowiadało na to, co OP wskazuje, jako lepiej sformułowane oszustwo ich pytania : tj. Bez sortowania)
ruffin
1
@Diego - Dlaczego uważasz, że to będzie wolniejsze niż odpowiedź, którą zaakceptowałeś?
Martin Smith
2
Spowoduje to zwrócenie wierszy do góry nogami. Następnie musisz ponownie złożyć zamówienie, aby odzyskać oryginalne zamówienie.
Mark
15

Jeśli chcesz wybrać ostatnie numery wierszy z tabeli.

Składnia będzie następująca

 select * from table_name except select top 
 (numbers of rows - how many rows you want)* from table_name

Te stwierdzenia działają, ale na różne sposoby. dzięki chłopaki.

 select * from Products except select top (77-10) * from Products

w ten sposób możesz uzyskać ostatnie 10 rzędów, ale kolejność pokaże malejący sposób

select top 10 * from products
 order by productId desc 

 select * from products
 where productid in (select top 10 productID from products)
 order by productID desc

 select * from products where productID not in 
 (select top((select COUNT(*) from products ) -10 )productID from products)
Prafulla Sutradhar
źródło
7

W bardzo ogólny sposób i do obsługi serwera SQL jest tutaj

SELECT TOP(N) *
FROM tbl_name
ORDER BY tbl_id DESC

a jeśli chodzi o wydajność, nie jest źle (mniej niż jedna sekunda na ponad 10000 rekordów na serwerze)

Hakan Fıstık
źródło
1
cóż, 10 000 rekordów to nic, o czym nie powinieneś myśleć o wydajności. Kiedy zaczynasz mówić o milionach rekordów, możesz zacząć myśleć o wydajności
Dom84
6

Czy „Id” jest indeksowany? Jeśli nie, to ważna rzecz (podejrzewam, że jest już indeksowana).

Czy musisz także zwrócić WSZYSTKIE kolumny? Możesz uzyskać znaczną poprawę szybkości, jeśli faktycznie potrzebujesz tylko mniejszego podzbioru kolumn, które można W PEŁNI pokryć indeks w kolumnie ID - np. Jeśli masz indeks NONCLUSTERED w kolumnie Id, bez innych pól zawartych w indeksie, wówczas musiałby przeprowadzić wyszukiwanie w indeksie klastrowym, aby faktycznie uzyskać zwrot pozostałych kolumn, co mogłoby znacznie wpłynąć na koszt zapytania. Jeśli jest to indeks CLUSTERED lub indeks NONCLUSTERED, który zawiera wszystkie inne pola, które chcesz zwrócić w zapytaniu, wszystko powinno być w porządku.

AdaTheDev
źródło
6

Najpierw otrzymujesz najwięcej rekordów z

 Declare @TableRowsCount Int
 select @TableRowsCount= COUNT(*) from <Your_Table>

I wtedy :

W programie SQL Server 2012

SELECT *
FROM  <Your_Table> As L
ORDER BY L.<your Field>
OFFSET <@TableRowsCount-@N> ROWS
FETCH NEXT @N ROWS ONLY;

W SQL Server 2008

SELECT *
FROM 
(
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS sequencenumber, *
FROM  <Your_Table>
    Order By <your Field>
) AS TempTable
WHERE sequencenumber > @TableRowsCount-@N 
Ardalan Shahgholi
źródło
4

Oto coś, czego możesz spróbować bez znaku, order byale myślę, że wymaga to, aby każdy wiersz był inny . Nto liczba żądanych wierszy, Lto liczba wierszy w tabeli.

select * from tbl_name except select top L-N * from tbl_name

Jak wspomniano wcześniej, zwracane wiersze są nieokreślone.

EDYCJA: to jest właściwie pies powolny. Tak naprawdę bez wartości.

Dzamo Norton
źródło
4
select * from (select top 6 * from vwTable order by Hours desc) T order by Hours
piąty
źródło
2

To zapytanie zwraca ostatnie N wierszy we właściwej kolejności, ale jego wydajność jest niska

select *
from (
    select top N *
    from TableName t
    order by t.[Id] desc
) as temp
order by temp.[Id]
Timberhill
źródło
2

użyj desc z orderby na końcu zapytania, aby uzyskać ostatnie wartości.

Sara
źródło
1

To może nie pasować do pytania, ale…

Klauzula OFFSET

OFFSET numberKlauzula pozwala przeskoczyć nad liczbą wierszy, a następnie powrót wiersze po tym.

Ten link do dokumentu prowadzi do Postgres; Nie wiem, czy dotyczy to Sybase / MS SQL Server.

Basil Bourque
źródło
1
DECLARE @MYVAR  NVARCHAR(100)
DECLARE @step  int
SET @step = 0;


DECLARE MYTESTCURSOR CURSOR
DYNAMIC 
FOR
SELECT col FROM [dbo].[table]
OPEN MYTESTCURSOR
FETCH LAST FROM MYTESTCURSOR INTO @MYVAR
print @MYVAR;


WHILE @step < 10
BEGIN   
    FETCH PRIOR FROM MYTESTCURSOR INTO @MYVAR
        print @MYVAR;
        SET @step = @step + 1;
END   
CLOSE MYTESTCURSOR
DEALLOCATE MYTESTCURSOR
Slava
źródło
1

MS nie obsługuje LIMIT w t-sql. W większości przypadków po prostu otrzymuję MAX (ID), a następnie odejmuję.

select * from ORDERS where ID >(select MAX(ID)-10 from ORDERS)

To zwróci mniej niż 10 rekordów, gdy identyfikator nie jest sekwencyjny.

olafk
źródło
0

Technika, której używam do odpytywania NAJNOWSZYCH wierszy w bardzo dużych tabelach (ponad 100 milionów lub ponad 1 miliard wierszy) ogranicza zapytanie do „czytania” tylko ostatniego procentu „N” z OSTATNICH WIERSZ. To są aplikacje ze świata rzeczywistego, na przykład robię to dla niehistorycznych ostatnich danych pogodowych, ostatnich wyszukiwań kanałów wiadomości lub ostatnich danych o lokalizacji GPS.

To ogromna poprawa wydajności jeśli na przykład wiesz na pewno, że Twoje wiersze znajdują się w ostatnich 5% w tabeli. Taki, że nawet jeśli w tabelach znajdują się indeksy, dodatkowo ogranicza to możliwości do tylko 5% wierszy w tabelach, które mają ponad 100 milionów lub ponad 1 miliard wierszy. Dzieje się tak zwłaszcza w przypadku, gdy starsze dane będą wymagały odczytu dysku fizycznego, a nie tylko logicznego w pamięci odczytów .

Jest to znacznie wydajniejsze niż SELECT TOP | PERCENT | LIMIT, ponieważ nie zaznacza wierszy, a jedynie ogranicza część danych do przeszukania.

DECLARE @RowIdTableA BIGINT
DECLARE @RowIdTableB BIGINT
DECLARE @TopPercent FLOAT

-- Given that there is an Sequential Identity Column
-- Limit query to only rows in the most recent TOP 5% of rows
SET @TopPercent = .05
SELECT @RowIdTableA = (MAX(TableAId) - (MAX(TableAId) * @TopPercent)) FROM TableA
SELECT @RowIdTableB = (MAX(TableBId) - (MAX(TableBId) * @TopPercent)) FROM TableB

SELECT *
FROM TableA a
INNER JOIN TableB b ON a.KeyId = b.KeyId
WHERE a.Id > @RowIdTableA AND b.Id > @RowIdTableB AND
      a.SomeOtherCriteria = 'Whatever'
CodeCowboyOrg
źródło
-1

Aby wyświetlić ostatnie 3 wiersze bez użycia order by:

select * from Lms_Books_Details where Book_Code not in 
 (select top((select COUNT(*) from Lms_Books_Details ) -3 ) book_code from Lms_Books_Details) 
abhinay
źródło
1
Nie zapewni to przewidywalnych rezultatów. Zgodnie z dokumentacją MSDN serwera Sql Server ( msdn.microsoft.com/en-us/library/ms189463.aspx ): „Gdy TOP jest używany w połączeniu z klauzulą ​​ORDER BY, zestaw wyników jest ograniczony do pierwszej liczby N zamówionych wiersze; w przeciwnym razie zwraca pierwszą liczbę N wierszy w niezdefiniowanej kolejności. "
caveman_dick
-1

Spróbuj użyć EXCEPTskładni.
Coś takiego:

   SELECT * 
    FROM   clientDetails 
    EXCEPT 
    (SELECT TOP (numbers of rows - how many rows you want) * 
     FROM   clientDetails) 
mayur godhani
źródło
Ta sama odpowiedź co @Prafulla Sutradhar
DMK,
-1

Może trochę późno, ale oto prosty wybór, który rozwiąże Twoje pytanie.

SELECT * FROM "TABLE" T ORDER BY "T.ID_TABLE" DESC LIMIT 5;
Lucas Orso
źródło