Làm thế nào để tôi làm top 1 trong Oracle?


251

Làm thế nào để tôi làm như sau?

select top 1 Fname from MyTbl

Trong Oracle 11g ?




3
Bạn có thể cho chúng tôi biết thứ tự mà bạn muốn 'top 1' không?
Andrew Wolfe

1
Trước hết bạn không bao giờ nên dựa vào công cụ DB để làm điều đó, bao giờ hết. Nếu bạn muốn biết những điều như vậy, hãy đặt một trình sắp xếp thứ tự. Khi bạn làm điều đó được đảm bảo rằng chúng sẽ được đánh số theo thứ tự chúng được chèn.
FlyingGuy 9/2/2015

1
Tài liệu rất hữu ích về chủ đề này sử dụng
Ilia Maskov

Câu trả lời:


257

Nếu bạn chỉ muốn một hàng được chọn đầu tiên, bạn có thể:

select fname from MyTbl where rownum = 1

Bạn cũng có thể sử dụng các hàm phân tích để đặt hàng và lấy đầu x:

select max(fname) over (rank() order by some_factor) from MyTbl

54
Điều này là tốt nếu bạn chỉ muốn 1 hàng và không quan tâm. Nếu bạn muốn các hàng cụ thể, như bản ghi gần đây nhất, bạn cần thực hiện sắp xếp trong mục chọn phụ, như câu trả lời của Vash. Oracle gán rownums trước khi sắp xếp.
Scott Bailey

4
@ Hủy bỏ yup. đúng rồi. Và Patrick, điểm tốt tôi nghĩ rằng cú pháp là không chính xác về điều đó. Nó thực sự nên là một giữ lại (dense_rank () cuối ...)
mcpeterson

2
Sự khác biệt giữa ví dụ thứ nhất và thứ hai là cái đầu tiên chọn một hàng (bất kỳ hàng nào, không có thứ tự). Ví dụ thứ hai nhận giá trị của hàng đầu tiên, mà không thực hiện truy vấn bên trong đơn hàng (theo ví dụ bên dưới).
JulesLt

3
Cú pháp không chính xác trong: chọn max (fname) trên (thứ hạng () theo thứ tự của some_factor) từ MyTbl
Stéphane Gerber

1
@jclozano "không phải là một chức năng rất nổi tiếng của nhà tiên tri" - Với sự tôn trọng, tôi xin khác biệt. Điều này quan trọng bởi vì "chức năng không được biết đến nhiều" có xu hướng ngụ ý tối nghĩa và do đó có thể đề nghị chúng ta nên tránh sử dụng. Điều này không tối nghĩa, và không nên tránh sử dụng nó.
Sepster 18/03/2015

166
SELECT *
  FROM (SELECT * FROM MyTbl ORDER BY Fname )
 WHERE ROWNUM = 1;

8
Câu trả lời này chính xác nhận được hàng TOP (sắp xếp các kết quả trước khi hạn chế trên ROWNUM).
JulesLt

Câu trả lời này không phải là một bản dịch chính xác - truy vấn ban đầu không có ĐẶT HÀNG B, NG, cũng không trả về tất cả các cột trong bảng.
Ngựa vằn OMG

Tôi đứng sửa (xem bên dưới). Sẽ chuyển phiếu khi thời gian đã hết.
JulesLt

7
@OMGPonies vâng. nhưng có lẽ đó là điều mà hầu hết mọi người thực sự muốn đến với trang này thông qua việc giải quyết vấn đề của họ
NimChimpsky

4
Điều này chắc chắn phải là câu trả lời chiến thắng trong chủ đề này. Tôi có thể thêm một lưu ý rằng đối với top Xmột người có thể thay đổi nó thànhWHERE ROWNUM <= X
SomethingS Something

31

Với Oracle 12c (tháng 6 năm 2013), bạn có thể sử dụng nó như sau.

SELECT * FROM   MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL          
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY

6
Lệnh thú vị, tôi đang sử dụng 12c ở đây và OFFSET 0 ROWSrõ ràng là không cần thiết, bạn có thể sử dụng FETCH NEXT 1 ROWS ONLYhoặc thậm chí FETCH FIRST ROW ONLY, thứ tự theo là quan trọng hoặc nó sẽ tương đương với chỉ sử dụng a WHERE rownum = 1. Tôi thậm chí đã thử nó trong một hướng dẫn ỨNG DỤNG NGOÀI TRỜI và nó hoạt động giống như chức năng TOP của Ms-SQL ở đó.
Rafael Merlin

Bạn nói đúng @RafaelMerlin. Sau bài đăng của bạn, tôi nhận ra rằng OFFSET 0 ROWS là không cần thiết. Sẽ rất hữu ích khi truy xuất dữ liệu giữa top X và top Y.
MSK


Cho đến nay rất tốt, với một điểm thiếu quan trọng đó là TIES. Tham khảo điều này cho các trường hợp khi mối quan hệ xảy ra cho phiên bản 12c +12c -
Barbaros Özhan

10

Bạn có thể sử dụng ROW_NUMBER()với một ORDER BYmệnh đề trong truy vấn phụ và sử dụng cột này để thay thế TOP N. Điều này có thể được giải thích từng bước.

Xem bảng dưới đây có hai cột NAMEDT_CREATED.

nhập mô tả hình ảnh ở đây

Nếu bạn chỉ cần mất hai ngày đầu tiên không phân biệt NAME, bạn có thể sử dụng truy vấn bên dưới. Logic đã được viết bên trong truy vấn

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
    -- Generates numbers in a column in sequence in the order of date
    SELECT ROW_NUMBER() OVER (ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

KẾT QUẢ

nhập mô tả hình ảnh ở đây

Trong một số tình huống, chúng ta cần chọn TOP Nkết quả tương ứng với từng kết quả NAME. Trong trường hợp như vậy, chúng ta có thể sử dụng PARTITION BYvới một ORDER BYmệnh đề trong truy vấn phụ. Tham khảo các truy vấn dưới đây.

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
  --Generates numbers in a column in sequence in the order of date for each NAME
    SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

KẾT QUẢ

nhập mô tả hình ảnh ở đây


1
Sử dụng ROW_NUMBER () ... là giải pháp chính xác hơn trong câu trả lời chủ đề. Một vấn đề với giải pháp này (và với biến thể tối đa (trường) cũng vậy) mà bạn không thể thực hiện những việc như "select ... (chọn ROW_NUMBER () ...) để cập nhật ;"
Alexo Po.

Và đôi khi nó rất quan trọng trong PL / SQL (xin lỗi, không thể chỉnh sửa nhận xét trước đó trong giới hạn 5 phút).
Alexo Po.

Trong trường hợp như vậy chúng ta có thể sử dụng CTE như ở phần bên ngoài. Đúng? @Alexo Po.
Sarath Avanavu

Tôi nghĩ rằng tôi không hiểu bạn. đối với mệnh đề cập nhật có thể được sử dụng khi ROWID được Oracle "bảo quản" dễ dàng. Vì vậy, nhóm (và nhóm do sử dụng mệnh đề phân tích) ẩn ROWID thực và các hàng không thể bị khóa. Và thứ hai, CTE ( with (select ... ) as mệnh đề) không thay đổi bất cứ điều gì cho vấn đề này, CTE chỉ nhằm mục đích đọc và hỗ trợ các truy vấn. Đúng? @Sarath Avanavu
Po.

Lưu ý về bản thân mình. Vấn đề với ROWID thực sự xảy ra cụ thể do điều kiện RNO <3 , trong trường hợp này giá trị của RNO không được kết nối với ROWID, đó là lý do tại sao Oracle không thể khóa các hàng.
Alexo Po.

9

Bạn có thể làm một cái gì đó như

    SELECT *
      FROM (SELECT Fname FROM MyTbl ORDER BY Fname )
 WHERE rownum = 1;

Bạn cũng có thể sử dụng các hàm phân tích RANK và / hoặc DENSE_RANK , nhưng ROWNUM có lẽ là dễ nhất.


1
bạn có thể vui lòng giúp đỡ với một số ví dụ về thứ hạng, v.v.
bćreehg

9
select * from (
    select FName from MyTbl
)
where rownum <= 1;

5

Sử dụng:

SELECT x.*
  FROM (SELECT fname 
          FROM MyTbl) x
 WHERE ROWNUM = 1

Nếu sử dụng Oracle9i +, bạn có thể xem xét việc sử dụng các hàm phân tích như ROW_NUMBER () nhưng chúng sẽ không hoạt động tốt như ROWNUM .


1
Câu trả lời hay nhưng chứa một lỗi đánh máy nhỏ. Nơi bạn nói Oracle9i + không nên là 8i? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/iêu
Ian Carpenter

@carpenteri: Đúng, phân tích có sẵn trong 8i - không thể nhớ chi tiết về, nhưng phân tích không thực sự có sẵn cho công chúng cho đến 9i.
Ngựa Non OMG

Nhận xét nhỏ - Câu trả lời của Vash bên dưới bao gồm ĐẶT HÀNG THEO truy vấn bên trong, điều này rất quan trọng nếu bạn muốn giá trị TOP của fname, thay vì 'đầu tiên' (có thể là bất cứ thứ gì, rất có thể là hàng đầu tiên được chèn). Có thể có giá trị chỉnh sửa?
JulesLt

@JulesLt: Truy vấn do OP cung cấp không bao gồm ORDER BY, vì vậy đây là câu trả lời đại diện và dịch chính xác cho cú pháp của Oracle.
Ngựa Non OMG

Sự hiểu lầm của tôi về cú pháp SQL SERVER TOP (sai lầm cho rằng nó tương tự như FIRST trong RANK, không phải ROWNUM). Bỏ phiếu lên.
JulesLt

3

Để chọn hàng đầu tiên từ một bảng và để chọn một hàng từ một bảng là hai nhiệm vụ khác nhau và cần một truy vấn khác nhau. Có nhiều cách có thể để làm như vậy. Bốn trong số đó là:

Đầu tiên

select  max(Fname) from MyTbl;

Thứ hai

select  min(Fname) from MyTbl;

Ngày thứ ba

select  Fname from MyTbl  where rownum = 1;

Thứ tư

select  max(Fname) from MyTbl where rowid=(select  max(rowid) from MyTbl)

3

Tôi đã có cùng một vấn đề và tôi có thể khắc phục vấn đề này bằng giải pháp này:

select a.*, rownum 
from (select Fname from MyTbl order by Fname DESC) a
where
rownum = 1

Bạn có thể đặt kết quả của bạn trước để có giá trị đầu tiên trên đầu trang.

Chúc may mắn

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.