2010-03-23 64 views
85

Tôi có một vấn đề lớn với một câu lệnh SQL trong Oracle. Tôi muốn chọn TOP 10 Records do STORAGE_DB đặt hàng không có trong danh sách từ một câu lệnh chọn khác.Oracle SELECT TOP 10 hồ sơ

một này làm việc tốt cho tất 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 nhận được một số loại hồ sơ "ngẫu nhiên". Tôi nghĩ bởi vì giới hạn sẽ diễn ra trước khi đặt hàng.

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

+0

Sao chép có thể xảy ra: http://stackoverflow.com/questions/2306744/oracle-sql-how-to-retrieve-highest-5-values-of-a-column – APC

Trả lời

142

Bạn sẽ cần phải đặt câu hỏi hiện tại của bạn trong subquery như sau:

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 đến kết quả sau khi nó đã được trả lại.
Bạn cần lọc kết quả sau khi nó đã được trả về, do đó, truy vấn con là bắt buộc. Bạn cũng có thể sử dụng chức năng RANK() để nhận kết quả Top-N.

Để biết hiệu suất, hãy thử sử dụng NOT EXISTS thay cho NOT IN. Xem this để biết thêm.

+0

NOT EXISTS không hoạt động trong trường hợp này (không hợp lệ toán tử quan hệ) APP_ID NOT EXISTS (SELEC ...) – opHASnoNAME

22

Liên quan đến hiệu suất kém, có nhiều thứ có thể xảy ra và đó thực sự phải là một câu hỏi riêng. Tuy nhiên, có một điều rõ ràng 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ỉ số sau đó viết lại này sẽ thực hiện tốt:

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 sẽ vô hiệu hóa việc sử dụng chỉ mục B-Tree.

10

Bạn nhận được một tập hợp ngẫu nhiên rõ ràng vì ROWNUM được áp dụng trước ORDER BY. Vì vậy, truy vấn của bạn có mười hàng đầu tiên và sắp xếp chúng.0 Để chọn mười lương cao nhất bạn nên sử dụng một hàm giải tích trong một subquery, sau đó lọc rằng:

select * from 
    (select empno, 
      ename, 
      sal, 
      row_number() over(order by sal desc nulls last) rnm 
    from emp) 
where rnm<=10 
11

Nếu bạn đang sử dụng Oracle 12c, bạn có thể sử dụng:

lấy N chỉ hàng tiếp theo Thông tin

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êm: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

+1

Đơn giản và chính xác. FETCH TIẾP THEO 10 ROWS CHỈ –

-4

Bạn có thể chỉ cần sử dụng Điều khoản TOP

CHỌN TOP 10 * FROM TABLE;

Hoặc

SELECT column_name (s) FROM tên_bảng ĐÂU ROWNUM < = số;

+1

Không có trong oracle SQL ... – Zafi

2

thử CHỌN * TỪ người dùng FETCH NEXT 10 ROWS ONLY;

+0

Chỉ hoạt động trên Oracle 12c trở lên – Volpato