Oracle CHỌN 10 hồ sơ hàng đầu


144

Tôi có một vấn đề lớn với Câu lệnh SQL trong Oracle. Tôi muốn chọn Bản ghi TOP 10 được STORAGE_DB đặt hàng không có trong danh sách từ một tuyên bố chọn khác.

Điều này hoạt động tốt cho tất cả các hồ sơ:

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
      STORAGE_GB IS NOT NULL AND 
        APP_ID NOT IN (SELECT APP_ID
                       FROM HISTORY
                        WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Nhưng khi tôi thêm

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Tôi đang nhận được một số loại Hồ sơ "ngẫu nhiên". Tôi nghĩ bởi vì giới hạn diễn ra trước khi đặt hàng.

Có ai có một giải pháp tốt? Vấn đề khác: Truy vấn này thực sự rất chậm (10k + hồ sơ)



Câu trả lời:


199

Bạn sẽ cần đặt truy vấn hiện tại của mình trong truy vấn con như dưới đây:

SELECT * FROM (
  SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC )
WHERE ROWNUM <= 10

Oracle áp dụng rownum cho kết quả sau khi nó được trả về.
Bạn cần lọc kết quả sau khi nó được trả về, vì vậy cần có một truy vấn con. Bạn cũng có thể sử dụng hàm RANK () để nhận kết quả Top-N.

Để thực hiện thử sử dụng NOT EXISTSthay thế NOT IN. Xem điều này để biết thêm.


KHÔNG EXISTS không hoạt động trong kịch bản này (toán tử quan hệ không hợp lệ) APP_ID KHÔNG EXISTS (SELEC ...)
opHASnoNAME

3
Một số người có thể nói rằng đây là thích hợp để tắt mọi người sang Oracle.
MrBoJangles

2
Kiểm tra FETCH NEXT N ROWS ONLYcâu trả lời dưới đây.
Mohamel

@Padmarag: Khi nào thì một rownum được áp dụng trong một truy vấn như thế này - Chọn * từ someTable trong đó someColumn = '123' và rownum <= 3. Có phải sau khi chọn kết quả từ [Chọn * từ someTable trong đó someColumn = '123']
Shirgill Farhan

55

Nếu bạn đang sử dụng Oracle 12c, hãy sử dụng:

FETCH TIẾP THEO N ROWS CHỈ

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC
FETCH NEXT 10 ROWS ONLY

Thông tin thêm: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html


2
đây là vàng so với câu trả lời khác
vào

Tôi đồng ý với aswzen
Austin Springer

1
Tôi muốn đưa ra câu trả lời này 100 upvote! Nhưng than ôi, tôi chỉ có một giải thưởng. Một là nó!
eidylon

23

Liên quan đến hiệu suất kém, có bất kỳ số lượng nào có thể, và nó thực sự phải là một câu hỏi riêng biệt. Tuy nhiên, có một điều rõ ràng có thể là một vấn đề:

WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Nếu HISTORY_DATE thực sự là một cột ngày và nếu nó có một chỉ mục thì việc viết lại này sẽ hoạt động tốt hơn:

WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')  

Điều này là do chuyển đổi kiểu dữ liệu vô hiệu hóa việc sử dụng chỉ mục B-Tree.



11

Bạn nhận được một bộ rõ ràng ngẫu nhiên vì ROWNUM được áp dụng trước khi ĐẶT HÀNG B .NG. Vì vậy, truy vấn của bạn lấy mười hàng đầu tiên và sắp xếp chúng.0 Để chọn mười mức lương hàng đầu, bạn nên sử dụng hàm phân tích trong truy vấn con, sau đó lọc:

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
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.