Tương đương với LIMIT cho DB2


91

Bạn làm như thế nào LIMITtrong DB2 cho iSeries?

Tôi có một bảng với hơn 50.000 bản ghi và tôi muốn trả về các bản ghi 0 đến 10.000 và các bản ghi 10.000 đến 20.000.

Tôi biết trong SQL, bạn viết LIMIT 0,10000ở cuối truy vấn cho 0 đến 10.000 và LIMIT 10000,10000ở cuối truy vấn cho 10000 đến 20.000

Vậy, điều này được thực hiện như thế nào trong DB2? Mã và cú pháp là gì? (ví dụ truy vấn đầy đủ được đánh giá cao)


ROW_NUMBER () chỉ được triển khai trong iSeries DB2 V5R4. Đối với các phiên bản trước, hãy thử sử dụng RRN () tương tự.
Paul Morgan,

RRN () hoàn toàn khác với row_number ().
Brandon Peterson

không làm việc cho tôi. Lỗi Sytanx.
elcool,

1
Hãy thử RRN (tên tệp) sẽ cung cấp số bản ghi tương đối vật lý của hàng. RRN sẽ không tuần tự và có thể bỏ qua số nếu các hàng đã bị xóa. RRN cũng sẽ không tuần tự theo khóa mà sẽ tuần tự dựa trên phép cộng nếu không có lần xóa nào xảy ra. Trong mọi trường hợp, RRN sẽ là duy nhất cho một hàng và có thể được sử dụng để chọn các tập con của bảng.
Paul Morgan,

1
DB2 hỗ trợ từ khóa giới hạn từ DB2 9.7.2 theo programmingzen.com/2010/06/02/...
Lakshman

Câu trả lời:


139

Sử dụng FETCH FIRST [n] ROWS ONLY:

http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.perf/db2z_fetchfirstnrows.htm

SELECT LASTNAME, FIRSTNAME, EMPNO, SALARY
  FROM EMP
  ORDER BY SALARY DESC
  FETCH FIRST 20 ROWS ONLY;

Để nhận được phạm vi, bạn phải sử dụng ROW_NUMBER()(kể từ v5r4) và sử dụng phạm vi đó trong WHEREmệnh đề: (bị đánh cắp từ đây: http://www.justskins.com/forums/db2-select-how-to-123209.html )

SELECT code, name, address
FROM ( 
  SELECT row_number() OVER ( ORDER BY code ) AS rid, code, name, address
  FROM contacts
  WHERE name LIKE '%Bob%' 
  ) AS t
WHERE t.rid BETWEEN 20 AND 25;

yeah, tôi cũng tìm thấy cái này, hehe. Tôi đã chỉnh sửa câu hỏi cùng lúc để cho biết rằng tôi cũng muốn có hàng giữa.
elcool

2
Bạn phải làm điều gì đó như thế này với ROW_NUMBER: justskins.com/forums/db2-select-how-to-123209.html
Joe

ROW_NUMBERkhông phải là một từ khóa hợp lệ. Nhưng thx đối với liên kết, nó đã cho tôi một ý tưởng và nó hoạt động.
elcool

13

Đã phát triển phương pháp này:

Bạn CẦN một bảng có giá trị duy nhất có thể được đặt hàng.

Nếu bạn muốn hàng 10.000 đến 25.000 và Bảng của bạn có 40.000 hàng, trước tiên, bạn cần lấy điểm bắt đầu và tổng số hàng:

int start = 40000 - 10000;

int total = 25000 - 10000;

Và sau đó chuyển chúng bằng mã vào truy vấn:

SELECT * FROM 
(SELECT * FROM schema.mytable 
ORDER BY userId DESC fetch first {start} rows only ) AS mini 
ORDER BY mini.userId ASC fetch first {total} rows only

Lưu ý rằng hàng thứ 10000 được bao gồm khỏi tập kết quả, hàng đầu tiên là hàng thứ 10001.
hơi xanh

1
Giải pháp thú vị. Tôi đã định sử dụng nó để tương thích với cơ sở dữ liệu thử nghiệm H2 ... Nhưng, thật đáng buồn, nó hoạt động chậm hơn ~ 30 lần so với phương pháp SELECT row_number () OVER (ORDER BY code).
manuna

9

Hỗ trợ cho OFFSET và LIMIT gần đây đã được thêm vào DB2 cho i 7.1 và 7.2. Bạn cần các cấp nhóm DB PTF sau để nhận được hỗ trợ này:

  • SF99702 cấp 9 dành cho IBM i 7.2
  • SF99701 cấp 38 dành cho IBM i 7.1

Xem tại đây để biết thêm thông tin: OFFSET và LIMIT tài liệu , Wiki nâng cao DB2 cho i


7

Đây là giải pháp tôi đã đưa ra:

select FIELD from TABLE where FIELD > LASTVAL order by FIELD fetch first N rows only;

Bằng cách khởi tạo LASTVAL thành 0 (hoặc '' cho trường văn bản), sau đó đặt nó thành giá trị cuối cùng trong tập hợp các bản ghi gần đây nhất, thao tác này sẽ chuyển qua bảng theo từng phần N bản ghi.


(Ban đầu tôi nghĩ rằng bạn đang đặt giá trị trong bảng, điều này sẽ gây ra vấn đề ngoạn mục trên một hệ thống đồng thời) Có, điều này sẽ hoạt động trong trường hợp bạn đang đọc tuần tự qua bảng, mặc dù bạn cần một số loại cột tie-breaker trong trường hợp Nnhỏ hơn số giá trị giống hệt nhau trong cột (mặc dù điều này cũng đúng khi sử dụng ROW_NUMBER()). Các giá trị ban đầu cũng phải được chọn cẩn thận - 0rõ ràng sẽ có vấn đề nếu cột chứa giá trị âm . Sẽ cần sự cẩn thận với nulls. Sẽ không hoạt động nếu các trang bị bỏ qua.
Clockwork-Muse

Cảm ơn đã nhận xét. Tôi nghĩ rằng có một giả định ngầm định rằng trường chúng tôi đang sử dụng để kiểm soát truy vấn là duy nhất và tăng đơn điệu. Tôi đồng ý rằng nếu những giả định đó không đúng, điều này sẽ không hoạt động để truy cập tất cả các bản ghi trong bảng. Và, tất nhiên, bạn chính xác rằng bạn phải bắt đầu với LASTVAL có ý nghĩa. Nói chung, tôi nghĩ bạn muốn bắt đầu với bất kỳ thứ gì được trả về bằng cách "chọn TỐI THIỂU (FIELD) từ BẢNG". Nếu trường được lập chỉ mục, hầu hết các công cụ db sẽ làm tốt hơn việc đọc toàn bộ bảng một cách tuần tự.
Tom Barron

2

Giải pháp của @ elcool là một ý tưởng thông minh, nhưng bạn cần biết tổng số hàng (thậm chí có thể thay đổi trong khi bạn đang thực hiện truy vấn!). Vì vậy, tôi đề xuất một phiên bản đã sửa đổi, rất tiếc là cần 3 truy vấn con thay vì 2:

select * from (
    select * from (
        select * from MYLIB.MYTABLE
        order by MYID asc 
        fetch first {last} rows only 
        ) I 
    order by MYID desc
    fetch first {length} rows only
    ) II
order by MYID asc

vị trí {last}cần được thay thế bằng số hàng của bản ghi cuối cùng tôi cần và {length}nên được thay thế bằng số hàng tôi cần, được tính bằng last row - first row + 1.

Ví dụ: nếu tôi muốn các hàng từ 10 đến 25 (tổng số 16 hàng), {last}sẽ là 25 và {length}sẽ là 25-10 + 1 = 16.


Tôi khinh thường những người không tán thành khi người khác mất thời gian trả lời câu hỏi của họ.
jp2code

1

Bạn cũng nên xem xét mệnh đề TỐI ƯU HÓA CHO n ROWS. Thông tin chi tiết về tất cả những điều này trong tài liệu DB2 LUW trong Hướng dẫn hạn chế chủ đề câu lệnh SELECT :

  • Mệnh đề OPTIMIZE FOR tuyên bố mục đích chỉ truy xuất một tập hợp con của kết quả hoặc ưu tiên chỉ truy xuất một vài hàng đầu tiên. Sau đó, trình tối ưu hóa có thể chọn các kế hoạch truy cập giảm thiểu thời gian phản hồi để truy xuất một vài hàng đầu tiên.

1

Thử cái này

SELECT * FROM
    (
        SELECT T.*, ROW_NUMBER() OVER() R FROM TABLE T
    )
    WHERE R BETWEEN 10000 AND 20000

0

Có 2 giải pháp để phân trang hiệu quả trên bảng DB2:

1 - kỹ thuật sử dụng hàm row_number () và mệnh đề OVER đã được trình bày trên một bài đăng khác ("SELECT row_number () OVER (ORDER BY ...)"). Trên một số bàn lớn, đôi khi tôi nhận thấy sự xuống cấp của màn trình diễn.

2 - kỹ thuật sử dụng con trỏ có thể cuộn. Việc triển khai phụ thuộc vào ngôn ngữ được sử dụng. Kỹ thuật đó có vẻ mạnh mẽ hơn trên các bàn lớn.

Tôi đã trình bày 2 kỹ thuật được thực hiện trong PHP trong một buổi hội thảo vào năm tới. Trang trình bày có sẵn trên liên kết này: http://gregphplab.com/serendipity/uploads/slides/DB2_PHP_Best_practices.pdf

Xin lỗi nhưng tài liệu này chỉ bằng tiếng Pháp.


0

Có các tùy chọn có sẵn sau: -

DB2 has several strategies to cope with this problem.
You can use the "scrollable cursor" in feature.
In this case you can open a cursor and, instead of re-issuing a query you can FETCH forward and backward.
This works great if your application can hold state since it doesn't require DB2 to rerun the query every time.
You can use the ROW_NUMBER() OLAP function to number rows and then return the subset you want.
This is ANSI SQL 
You can use the ROWNUM pseudo columns which does the same as ROW_NUMBER() but is suitable if you have Oracle skills.
You can use LIMIT and OFFSET if you are more leaning to a mySQL or PostgreSQL dialect.  
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.