SQL Server ВИБІРУЙТЕ ОСТАННІ N рядків


139

Це відоме питання, але найкращим рішенням, який я знайшов, є щось на зразок:

SELECT TOP N *
FROM MyTable
ORDER BY Id DESC

У мене стіл з великою кількістю рядків. Неможливо використовувати цей запит, оскільки це займає багато часу. Тож як я можу вибрати останні N рядків без використання ЗАМОВЛЕННЯ?

EDIT

Вибачте, повторне питання цього


Що означає "останній N"? Без замовлення "останній N" не має великого сенсу. Якщо ви маєте на увазі "останній N буде вставлено", ви не можете розраховувати на SQL Server, щоб надати це вам - ви повинні використовувати пункт ORDER BY.
Даніель Реншоу

@Daniel Renshaw: Останній N таблиці, не змушуючи SQL Server замовляти всю таблицю, оскільки вона стає дуже повільною
Дієго

Запит у вашому питанні - найкращий спосіб. Якщо idіндексувати, то він просто сканує цей індекс у зворотному напрямку та зупиняється після перших 5 рядків. Якщо він не індексований, знадобиться зробити TOP Nсортування. Це не буде гірше, ніж будь-який інший спосіб зробити це. Це не сортує всю таблицю (хоча знадобиться сканувати всю таблицю)
Мартін Сміт,

Відповіді:


38

Ви можете це зробити, скориставшись також функцією ROW NUMBER BY PARTITION. Чудовий приклад можна знайти тут :

Я використовую таблицю "Замовлення" бази даних Northwind ... Тепер давайте знайдемо останні 5 замовлень, розміщених співробітником 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

1
Функція "РІЧНИЙ НОМЕР ПО ПАРТІЄНІ" також використовує сортування. Вам потрібно сортувати таблицю, щоб призначити номери рядків для кожного запису ...
Садхір

Це правда, але без якогось характеру це просто не буде працювати, найкраще рішення - індексувати основні стовпці, що потрапляють, та виконувати щось на зразок вищезазначеного запиту.
JonVD

101

Ви можете змусити SQL-сервер вибирати останні N рядків за допомогою цього SQL:

select * from tbl_name order by id desc limit N;

2
Як щодо сумісності версій?
Fractaliste

63
Це не працює в SQL Server. Схоже, функція MySQL, PostgreSQL та SQLite.
Тім Фрізен

3
Всі перераховані продукти, безумовно, є SQL-серверами. Якщо ви хочете поговорити про MS SQL-сервер, чому б не назвати його так?
gena2x

4
Я розгублений, питання задає питання про те, як створити обраний запит "без використання ЗАМОВЛЕННЯ ПО", а запит вибору у вашій відповіді "замовити за" Це якийсь "порядок за" без "наказ за"?
Роберт Сінклер

5
@ gena2x це питання позначено тегом SQL Server. Цей тег посилається на Microsoft SQL Server.
Мартін Сміт

51

Я перевірив код JonVD, але виявив, що він дуже повільний, 6 секунд.

Цей код зайняв 0 с.

SELECT TOP(5) ORDERID, CUSTOMERID, OrderDate    
FROM Orders where EmployeeID=5    
Order By OrderDate DESC

4
Скільки рядків ?? Коли у вас буде багато рядків, які можуть бути дійсно повільними
Дієго

@Diego Чому це? Якщо ви OrderDateіндексували, слід вибрати однаково швидкий вибір першого чи останнього N рядків запиту. Я усвідомлюю, що є шанс OrderDateдобре співвідноситись із замовленням, але в кращому випадку це побічний ефект, і все-таки потрібно сканувати таблицю, ні? (І я не думаю, що це відповідає на те, на що вказує ОП як на краще
формульований дуб

1
@Diego - Чому ти вважаєш, що це буде повільніше, ніж відповідь, яку ти прийняв?
Мартін Сміт

2
Це повертає рядки догори дном. Тоді вам доведеться повторно замовити їх, щоб повернути початкове замовлення.
Марк

15

Якщо ви хочете вибрати останні таблиці рядків із таблиці.

Синтаксис буде подібний

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

Ці твердження працюють, але різними способами. дякую, хлопці

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

таким чином, ви можете отримати останні 10 рядів, але замовлення покаже низхідний шлях

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)

7

В дуже загальному вигляді і підтримка SQL-сервера тут є

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

а для продуктивності це непогано (менше однієї секунди для понад 10 000 записів на серверній машині)


1
ну 10 000 записів - це не те, що вам слід зауважити щодо продуктивності. Коли ви починаєте говорити про мільйони записів, то можете починати думати про продуктивність
Dom84

6

Чи індексовано "Id"? Якщо ні, це важливо зробити (я підозрюю, що це вже індексується).

Також потрібно повернути ВСІ стовпці? Ви можете досягти значного покращення швидкості, якщо вам дійсно потрібен лише менший підмножина стовпців, який може бути ПОСТАВЛЕНО за допомогою індексу в стовпці ідентифікатора - наприклад, якщо у вас стовпчик "НЕЗАБАВЛЕНО" в стовпці Id, без жодного іншого поля, включені до індексу, тоді доведеться провести пошук кластерного індексу, щоб фактично отримати решту стовпців для повернення, і це може скласти велику вартість запиту. Якщо це індекс CLUSTERED або NONCLUSTERED, що включає всі інші поля, які ви хочете повернути у запиті, то вам слід буде добре.


6

Спочатку ви найбільше отримуєте підрахунок записів

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

І потім :

У SQL Server 2012

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

У 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 

4

Ось щось можна спробувати без цього, order byале я думаю, що це вимагає, щоб кожен рядок був унікальним. N- кількість потрібних рядків, Lце кількість рядків у таблиці.

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

Як зазначалося раніше, які рядки повертаються, не визначено.

EDIT: це насправді собака повільно. Насправді немає ніякої цінності.


4
select * from (select top 6 * from vwTable order by Hours desc) T order by Hours

2

Цей запит повертає останні N рядків у правильному порядку, але його ефективність погана

select *
from (
    select top N *
    from TableName t
    order by t.[Id] desc
) as temp
order by temp.[Id]

2

використовувати desc з orderby в кінці запиту, щоб отримати останні значення.


1

Це може бути не зовсім правильним підходом до питання, але ...

Пункт OFFSET

Цей OFFSET numberпункт дозволяє пропускати через ряд рядків, а потім повертати рядки після цього.

Це посилання на doc - на Postgres; Я не знаю, чи стосується це Sybase / MS SQL Server.


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

1

MS не підтримує LIMIT в t-sql. У більшості випадків я просто отримую MAX (ID), а потім віднімаю.

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

Це поверне менше 10 записів, коли ID не є послідовним.


0

Метод, який я використовую для запиту найпопулярніших рядків у дуже великих таблицях (100+ мільйонів або 1+ мільярдів рядків) , обмежує запит на "читання" лише останнього "N" відсотка ПОСЛІДНИХ РЯДІВ. Це додатки в реальному світі, наприклад, я роблю це для неісторичних останніх погодних даних або останніх пошуків каналів новин або останніх даних точок даних про місцезнаходження GPS.

Це величезне поліпшення продуктивності, якщо ви точно знаєте, що ваші рядки є, наприклад, в останніх 5% таблиці. Такий, що навіть якщо на Таблицях є індекси, це додатково обмежує можливості лише 5% рядків у таблицях, що містять 100+ мільйонів або 1+ мільярдів рядків. Особливо це стосується випадків, коли для старих даних будуть потрібні зчитування фізичного диска, а не лише зчитування з Logical In Memory .

Це набагато ефективніше, ніж SELECT TOP | ПОСЛУГИ | LIMIT, оскільки він не вибирає рядки, а лише обмежує частину даних, які потрібно шукати.

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'

-1

Для відображення останніх 3 рядків без використання 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) 

1
Це не дасть передбачуваних результатів. Відповідно до документів MSDN сервера Sql ( msdn.microsoft.com/en-us/library/ms189463.aspx ): "Коли TOP використовується спільно з пунктом ORDER BY, набір результатів обмежується першим N числом упорядкованих рядки, інакше повертає перше N число рядків у невизначеному порядку. "
caveman_dick

-1

Спробуйте використовувати EXCEPTсинтаксис.
Щось на зразок цього:

   SELECT * 
    FROM   clientDetails 
    EXCEPT 
    (SELECT TOP (numbers of rows - how many rows you want) * 
     FROM   clientDetails) 

Відповідь така ж, як і @Prafulla Sutradhar
DMK

-1

Можливо, трохи пізно, але ось простий вибір, який вирішить ваше питання.

SELECT * FROM "TABLE" T ORDER BY "T.ID_TABLE" DESC LIMIT 5;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.