Thực hiện chức năng phân trang (bỏ qua / lấy) với truy vấn này


138

Tôi đã cố gắng hiểu một chút về cách triển khai phân trang tùy chỉnh trong SQL, ví dụ như đọc các bài viết như thế này .

Tôi có truy vấn sau đây, hoạt động hoàn hảo. Nhưng tôi muốn thực hiện phân trang với cái này.

SELECT TOP x PostId FROM ( SELECT PostId, MAX (Datemade) as LastDate
 from dbForumEntry 
 group by PostId ) SubQueryAlias
 order by LastDate desc

Tôi muốn gì

Tôi có bài viết diễn đàn, với các mục liên quan. Tôi muốn nhận các bài đăng với các mục được thêm mới nhất, vì vậy tôi có thể chọn các bài đăng được tranh luận gần đây.

Bây giờ, tôi muốn có thể nhận được "top 10 đến 20 bài đăng hoạt động gần đây", thay vì "top 10".

Tôi đã thử những gì

Tôi đã cố gắng thực hiện các chức năng ROW như một trong bài viết, nhưng thực sự không có may mắn.

Bất kỳ ý tưởng làm thế nào để thực hiện nó?

Câu trả lời:


288

Trong SQL Server 2012, nó rất dễ

SELECT col1, col2, ...
 FROM ...
 WHERE ... 
 ORDER BY -- this is a MUST there must be ORDER BY statement
-- the paging comes here
OFFSET     10 ROWS       -- skip 10 rows
FETCH NEXT 10 ROWS ONLY; -- take 10 rows

Nếu chúng ta muốn bỏ qua ĐẶT HÀNG, chúng ta có thể sử dụng

SELECT col1, col2, ...
  ...
 ORDER BY CURRENT_TIMESTAMP
OFFSET     10 ROWS       -- skip 10 rows
FETCH NEXT 10 ROWS ONLY; -- take 10 rows

(Tôi muốn đánh dấu rằng đó là một bản hack - nhưng nó được sử dụng, ví dụ như bởi NHibernate.

để trả lời câu hỏi:

--SQL SERVER 2012
SELECT PostId FROM 
        ( SELECT PostId, MAX (Datemade) as LastDate
            from dbForumEntry 
            group by PostId 
        ) SubQueryAlias
 order by LastDate desc
OFFSET 10 ROWS -- skip 10 rows
FETCH NEXT 10 ROWS ONLY; -- take 10 rows

Các từ khóa mới offsetfetch next(chỉ tuân theo các tiêu chuẩn SQL) đã được giới thiệu.

Nhưng tôi đoán rằng, bạn không sử dụng SQL Server 2012 , phải không? Trong phiên bản trước, nó hơi khó (một chút). Dưới đây là so sánh và ví dụ cho tất cả các phiên bản máy chủ SQL: tại đây

Vì vậy, điều này có thể hoạt động trong SQL Server 2008 :

-- SQL SERVER 2008
DECLARE @Start INT
DECLARE @End INT
SELECT @Start = 10,@End = 20;


;WITH PostCTE AS 
 ( SELECT PostId, MAX (Datemade) as LastDate
   ,ROW_NUMBER() OVER (ORDER BY PostId) AS RowNumber
   from dbForumEntry 
   group by PostId 
 )
SELECT PostId, LastDate
FROM PostCTE
WHERE RowNumber > @Start AND RowNumber <= @End
ORDER BY PostId

Cảm ơn rất nhiều! Đó là một câu trả lời thực sự tốt! Chỉ có câu hỏi về sql 2008 một. Tôi muốn ORDER BY xảy ra trước WHERE, vì hiện tại nó sẽ sắp xếp tập hợp con, nhưng chúng tôi muốn chọn một cái gì đó từ toàn bộ ... Có ý tưởng nào không? :) Một lần nữa, cảm ơn
Lars Holdgaard

2
Nếu tôi hiểu bạn chính xác, bạn muốn sắp xếp theo LastDate, phải không? sau đó chúng ta có thể thay đổi mệnh đề OVER () theo cách này: ROW_NUMBER () OVER (ĐẶT HÀNG B MAXNG MAX (DHRade) desc ). Và loại bỏ thứ tự cuối cùng của PostId . Bây giờ CTE nên được sắp xếp 'sớm hơn' khi cần thiết. chính xác?
Radim Köhler

1
Cảm ơn bạn đã giúp đỡ, một lưu ý về mẫu năm 2012, thứ tự là bắt buộc, tôi đã thử điều này mà không theo thứ tự và có lỗi "cú pháp không chính xác" không biết điều gì sai cho đến khi tôi nhìn vào cú pháp MSDN và biết rằng thứ tự đó là bắt buộc .
Esen

Là hàng đầu tiên 1 hay 0? Nên ở đâu WHERE RowNumber >= @Start AND RowNumber < @Endđể có 1000 hàng đầu tiên nếu @Startlà 0 và @Endlà 1000?
CWSpear

1
Cảm ơn bạn rất nhiều
Mafii



5

SQL 2008

Câu trả lời của Radim Köhler hoạt động, nhưng đây là phiên bản ngắn hơn:

select top 20 * from
(
select *,
ROW_NUMBER() OVER (ORDER BY columnid) AS ROW_NUM
from tablename
) x
where ROW_NUM>10

Nguồn: https://forums.asp.net/post/4033909.aspx


-1

Bạn có thể sử dụng truy vấn lồng nhau để phân trang như sau:

Phân trang từ 4 Hàng thành 8 Hàng trong đó CustomerIdkhóa chính .

SELECT Top 5 * FROM Customers
WHERE Country='Germany' AND CustomerId Not in (SELECT Top 3 CustomerID FROM Customers
WHERE Country='Germany' order by city) 
order by city;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.