2012-11-16 28 views
11

Tôi đang tìm một số expresion như thế này (sử dụng SQL Server 2008)Return hàng giữa một phạm vi cụ thể, với một tuyên bố chọn

SELECT TOP 10 columName FROM tableName 

Nhưng thay vì rằng tôi cần các giá trị từ 10 đến 20. Và Tôi tự hỏi nếu có một cách để làm điều đó bằng cách sử dụng chỉ có một câu lệnh SELECT.

Ví dụ này là vô ích:

SELECT columName FROM 
(SELECT ROW_NUMBER() OVER(ORDER BY someId) AS RowNum, * FROM tableName) AS alias 
WHERE RowNum BETWEEN 10 AND 20 

Bởi vì khung bên chọn đã được trả lại tất cả các kết quả, và tôi đang tìm cách để tránh điều đó, do hiệu suất.

Trả lời

0

Sử dụng SQL Server 2012 để tìm nạp/bỏ qua!

SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty, UnitPrice, LineTotal 
FROM AdventureWorks2012.Sales.SalesOrderDetail 
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY; 

Không có gì tốt hơn bạn mô tả cho các phiên bản cũ hơn của máy chủ sql. Có thể sử dụng CTE, nhưng không tạo ra sự khác biệt.

WITH NumberedMyTable AS 
(
    SELECT 
     Id, 
     Value, 
     ROW_NUMBER() OVER (ORDER BY Id) AS RowNumber 
    FROM 
     MyTable 
) 
SELECT 
    Id, 
    Value 
FROM 
    NumberedMyTable 
WHERE 
    RowNumber BETWEEN @From AND @To 

hoặc, bạn có thể xóa 10 hàng hàng đầu và sau đó nhận 10 hàng tiếp theo, nhưng tôi tăng gấp đôi bất kỳ ai muốn thực hiện điều đó.

+1

Nâng cấp lên SQL Server 2012 thường không phải là tùy chọn "chụp ngón tay của bạn". Và tôi cho rằng có * câu trả lời tốt hơn trong các phiên bản cũ của SQL Server. Ví dụ: tại sao không chỉ lấy các giá trị * khóa * khi áp dụng số hàng, sau đó kết nối đầu ra đó (sẽ có * nhiều * skinner) với bảng? –

+0

@AaronBertrand, bạn nói đúng.Tôi hoàn toàn đồng ý rằng việc nâng cấp không dễ dàng, nhưng trong trường hợp OP đang sử dụng tuyên bố này rất nhiều và thực sự quan tâm đến hiệu suất, đây là điều mà anh/cô ấy có thể cân nhắc. – RAS

7

Có một mẹo với row_number không liên quan đến sắp xếp tất cả các hàng.

Hãy thử điều này:

SELECT columName 
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (select NULL as noorder)) AS RowNum, * 
     FROM tableName 
    ) as alias 
WHERE RowNum BETWEEN 10 AND 20 

Bạn không thể sử dụng một hằng số trong order by. Tuy nhiên, bạn có thể sử dụng một biểu thức đánh giá đến một hằng số. SQL Server nhận ra điều này và chỉ trả về các hàng như đã gặp, được liệt kê đúng.

+0

Tôi không chắc chắn cách thức này có thể hữu ích. Sẽ không phải là trường hợp nếu ROW_NUMBER() được áp dụng mà không phân loại rõ ràng, phân trang sẽ vô dụng (được trình bày theo thứ tự tùy ý)? –

+0

Tôi đã tìm thấy rằng việc sử dụng cấu trúc này, số hàng được chỉ định khi các hàng được tạo. Hoặc, cụ thể hơn, có vẻ như không có phân loại trung gian của bảng (ít nhất là về hiệu suất). Tôi thường sử dụng điều này để gán các id số cho các hàng khi sử dụng 'SELECT INTO'. Và, có, số hàng là tùy ý, nhưng các truy vấn trong câu hỏi không có mệnh đề 'order by'. –

+0

Nhưng một lần nữa, quan sát <> đảm bảo. Tôi chắc chắn rằng thứ tự trình bày là quan trọng, nhưng nó thường bị bỏ qua những câu hỏi này một cách ngắn gọn - không phải vì họ muốn khuyến khích các câu trả lời có khả năng cung cấp các kết quả tùy ý. –

3

Tại sao bạn nghĩ SQL Server sẽ đánh giá toàn bộ truy vấn bên trong? Giả sử cột sắp xếp của bạn được lập chỉ mục, nó sẽ chỉ đọc 20 giá trị đầu tiên. Nếu bạn thực sự lo lắng, bạn có thể làm điều này:

Select 
    Id 
From (
    Select Top 20 -- note top 20 
    Row_Number() Over(Order By Id) As RowNum, 
    Id 
    From 
    dbo.Test 
    Order By 
    Id 
) As alias 
Where 
    RowNum Between 10 And 20 
Order By 
    Id 

nhưng tôi chắc chắn rằng kế hoạch truy vấn cũng giống nhau.

(Thực sự) Cố định theo nhận xét của Aaron.

http://sqlfiddle.com/#!3/db162/6

+0

Về mặt kỹ thuật bạn muốn có một ORDER BY trong đó. Lựa chọn bên trong không được * đảm bảo * để trả về các hàng theo thứ tự chúng được ROW_NUMBER() áp dụng, mặc dù đó là những gì bạn có thể quan sát trong hầu hết các trường hợp. Cũng lưu ý rằng truy vấn bên trong ngày càng đắt hơn khi bạn di chuyển qua trang thứ 2, thứ 3, ... thứ 500. Lý tưởng nhất là một giải pháp sẽ cung cấp hiệu suất tuyến tính. –

+0

Bạn sẽ cần một cái gì đó giống như bỏ qua danh sách để làm điều đó một cách không quốc tịch. Tôi không nghĩ rằng SQL Server có một cấu trúc chỉ mục cung cấp hiệu suất không đổi để di chuyển đến vị trí thứ n trong một chỉ mục. Bạn có thể làm tốt hơn nếu tập hợp cơ bản không thay đổi, sau đó bạn có thể tính toán trước bù trừ trang và lưu trữ chúng trong một bảng riêng biệt. Cảm ơn bạn đã sửa yêu cầu sắp xếp lại truy vấn bên ngoài. – Laurence

+0

Truy vấn bên trong thực sự là một truy vấn cần một thứ tự (bên ngoài làm cho mục đích trình bày, nhưng bên trong cần một để đảm bảo lựa chọn hàng chính xác). Ngoài ra tôi đã không đề xuất bất cứ điều gì về việc cung cấp không trạng thái ... người dùng đã mong đợi rằng dữ liệu cơ bản có thể thay đổi trong khi cuộn. Nhưng tìm đến trang thứ n * có thể * tương đối tuyến tính trong SQL Server, nhưng không phải nếu bạn làm như vậy bằng 'SELECT TOP 10 FROM (SELECT TOP (trang * pagesize) TỪ bảng lớn)' –

0

Thêm một lựa chọn

SELECT TOP(11) columName 
FROM dbo.tableName 
ORDER BY 
CASE WHEN ROW_NUMBER() OVER (ORDER BY someId) BETWEEN 10 AND 20 
    THEN ROW_NUMBER() OVER (ORDER BY someId) ELSE NULL END DESC 
0

Bạn có thể tạo một bảng tạm thời được đặt hàng theo cách bạn muốn thích:

SELECT ROW_NUMBER() OVER (ORDER BY someId) AS ROWNUM , * FROM tableName vào ## tempTable ...

Bằng cách đó bạn có danh sách thứ tự hàng S. và chỉ có thể truy vấn theo số hàng các lần tiếp theo thay vì thực hiện truy vấn bên trong nhiều lần.

Các vấn đề liên quan