ฉันจะ จำกัด จำนวนแถวที่ส่งคืนโดยเคียวรี Oracle หลังจากสั่งซื้อได้อย่างไร?


1032

มีวิธีที่จะทำให้OracleแบบสอบถามทำงานเหมือนมีMySQL limitประโยคหรือไม่?

ในMySQLฉันสามารถทำสิ่งนี้:

select * 
from sometable
order by name
limit 20,10

เพื่อรับแถวที่ 21 ถึงแถวที่ 30 (ข้ามแถวแรก 20 ให้อีก 10 แถวถัดไป) แถวจะถูกเลือกหลังแถวorder byดังนั้นจึงเริ่มต้นด้วยชื่อที่ 20 ตามตัวอักษร

ในOracleสิ่งเดียวที่คนพูดถึงคือrownumคอลัมน์หลอก แต่มันถูกประเมินมาก่อน order byซึ่งหมายความว่า:

select * 
from sometable
where rownum <= 10
order by name

จะส่งกลับชุดสุ่มสิบแถวเรียงตามชื่อซึ่งมักจะไม่ใช่สิ่งที่ฉันต้องการ นอกจากนี้ยังไม่อนุญาตให้ระบุการชดเชย


16
มาตรฐานใน SQL: 2008
dalle

14
จำกัด ประกาศโดยทอม Kyte สำหรับ Oracle 12c ...
wolφi

14
กำลังดึงหน้าถัดไปในชุดผลลัพธ์หรือไม่
Mathieu Longtin

3
@YaroslavShabalin โดยเฉพาะการค้นหาเพจใช้รูปแบบนี้ตลอดเวลา แอพที่มีฟังก์ชั่นการค้นหาเกือบทุกประเภทจะใช้งาน กรณีการใช้งานอื่นจะโหลดเพียงส่วนหนึ่งของรายการแบบยาวหรือฝั่งไคลเอ็นต์ตารางและให้ผู้ใช้มีตัวเลือกเพื่อขยาย
jpmc26

3
@YaroslavShabalin ORDER BYคุณไม่สามารถรับชุดผลลัพธ์ที่แตกต่างกันยกเว้นในกรณีที่มีการเปลี่ยนแปลงข้อมูลพื้นฐานเพราะ นั่นคือจุดรวมของการสั่งซื้อครั้งแรก หากข้อมูลพื้นฐานเปลี่ยนแปลงและชุดผลลัพธ์ของคุณเปลี่ยนไปเพราะเหตุใดจึงไม่แสดงผลลัพธ์ที่อัปเดตให้ผู้ใช้แทนข้อมูลที่ล้าสมัย นอกจากนี้การจัดการของรัฐก็เป็นสิ่งที่ต้องหลีกเลี่ยงให้มากที่สุด มันเป็นแหล่งที่มาของความซับซ้อนและข้อบกพร่อง; นั่นเป็นเหตุผลที่ฟังก์ชั่นได้รับความนิยมมาก และเมื่อไหร่ที่คุณจะรู้ว่าหมดอายุผลลัพธ์ทั้งหมดที่ตั้งไว้ในหน่วยความจำ? ในเว็บคุณไม่มีทางรู้ว่าเมื่อใดที่ผู้ใช้ออกไป
jpmc26

คำตอบ:


620

เริ่มต้นจาก Oracle 12c R1 (12.1) มีเป็นข้อ จำกัด แถว ไม่ใช้LIMITไวยากรณ์ที่คุ้นเคยแต่สามารถทำงานได้ดีขึ้นด้วยตัวเลือกเพิ่มเติม คุณสามารถค้นหาไวยากรณ์เต็มได้ที่นี่ (อ่านเพิ่มเติมเกี่ยวกับวิธีการทำงานภายในของ Oracle ในคำตอบนี้ )

เพื่อตอบคำถามเดิมนี่คือแบบสอบถาม:

SELECT * 
FROM   sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

(สำหรับ Oracle เวอร์ชันก่อนหน้าโปรดอ้างอิงคำตอบอื่น ๆ ในคำถามนี้)


ตัวอย่าง:

ตัวอย่างต่อไปนี้ถูกยกมาจากหน้าเชื่อมโยงในความหวังในการป้องกันการเน่าลิงค์

ติดตั้ง

CREATE TABLE rownum_order_test (
  val  NUMBER
);

INSERT ALL
  INTO rownum_order_test
SELECT level
FROM   dual
CONNECT BY level <= 10;

COMMIT;

มีอะไรอยู่ในโต๊ะบ้าง

SELECT val
FROM   rownum_order_test
ORDER BY val;

       VAL
----------
         1
         1
         2
         2
         3
         3
         4
         4
         5
         5
         6
         6
         7
         7
         8
         8
         9
         9
        10
        10

20 rows selected.

รับNแถวแรก

SELECT val
FROM   rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY;

       VAL
----------
        10
        10
         9
         9
         8

5 rows selected.

ได้รับครั้งแรกNแถวถ้าNTHแถวมีความสัมพันธ์ได้รับทั้งหมดแถวผูก

SELECT val
FROM   rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS WITH TIES;

       VAL
----------
        10
        10
         9
         9
         8
         8

6 rows selected.

x% ของแถวสูงสุด

SELECT val
FROM   rownum_order_test
ORDER BY val
FETCH FIRST 20 PERCENT ROWS ONLY;

       VAL
----------
         1
         1
         2
         2

4 rows selected.

การใช้อ็อฟเซ็ตมีประโยชน์มากสำหรับการแบ่งหน้า

SELECT val
FROM   rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY;

       VAL
----------
         3
         3
         4
         4

4 rows selected.

คุณสามารถรวมการชดเชยกับเปอร์เซ็นต์

SELECT val
FROM   rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 20 PERCENT ROWS ONLY;

       VAL
----------
         3
         3
         4
         4

4 rows selected.


1
เพียงเพื่อขยาย: OFFSET FETCHไวยากรณ์เป็นไวยากรณ์น้ำตาล รายละเอียด
Lukasz Szozda

793

คุณสามารถใช้คิวรีย่อยสำหรับสิ่งนี้ได้

select *
from  
( select * 
  from emp 
  order by sal desc ) 
where ROWNUM <= 5;

ดูหัวข้อOn ROWNUM และ จำกัด ผลลัพธ์ที่ Oracle / AskTom สำหรับข้อมูลเพิ่มเติม

อัปเดต : เพื่อ จำกัด ผลลัพธ์ที่มีขอบเขตที่ต่ำกว่าและสูงกว่าเล็กน้อย

select * from 
( select a.*, ROWNUM rnum from 
  ( <your_query_goes_here, with order by> ) a 
  where ROWNUM <= :MAX_ROW_TO_FETCH )
where rnum  >= :MIN_ROW_TO_FETCH;

(คัดลอกจากบทความ AskTom- ที่ระบุ)

อัปเดต 2 : เริ่มต้นด้วย Oracle 12c (12.1) มีไวยากรณ์เพื่อ จำกัด แถวหรือเริ่มเมื่อออฟเซ็ต

SELECT * 
FROM   sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

ดูคำตอบนี้สำหรับตัวอย่างเพิ่มเติม ขอบคุณ Krumia สำหรับคำใบ้


5
นี่เป็นวิธีที่จะทำ แต่ต้องระวัง (ตามที่ขอให้บทความ Tom พูด) ประสิทธิภาพของการค้นหาจะลดลงเมื่อจำนวนแถวสูงสุดของคุณเพิ่มขึ้น นี่เป็นทางออกที่ดีสำหรับผลลัพธ์การสืบค้นที่คุณต้องการเห็นเพียงไม่กี่หน้าแรก แต่ถ้าคุณใช้สิ่งนี้เป็นกลไกสำหรับการใช้รหัสต่อหน้าตลอดทั้งตารางคุณจะดีกว่าการปรับรหัสของคุณใหม่
Chris Gill

1
+1 เวอร์ชันที่ต่ำกว่า / สูงกว่าของคุณช่วยให้ฉันสามารถแก้ไขปัญหาที่มีคำสั่ง rownum ที่ จำกัด ขอบเขตบนเท่านั้นซึ่งทำให้การสืบค้นของฉันช้าลงอย่างมาก
เคลวิน

1
Leigh Riffel "โซลูชันการวิเคราะห์ที่มีเพียงหนึ่งแบบสอบถามซ้อน" เป็นหนึ่ง
Darren Hicks

7
บทความ AskTom มีคำใบ้ของเครื่องมือเพิ่มประสิทธิภาพเช่นกันซึ่งใช้ SELECT / * + FIRST_ROWS (n) / a , rownum rnum สแลชปิดควรนำหน้าด้วยเครื่องหมายดอกจัน ดังนั้นขัดมันออกมา
David Mann

1
โปรดทราบว่าสำหรับ Oracle 11 ตัวเลือกภายนอกที่มี ROWNUM จะป้องกันไม่ให้คุณเรียกใช้ deleteRow ใน UpdatableResultSet (ด้วย ORA-01446) - รอคอยการเปลี่ยนแปลง 12c R1!
nsandersen

185

ฉันทำการทดสอบประสิทธิภาพสำหรับแนวทางต่อไปนี้:

Asktom

select * from (
  select a.*, ROWNUM rnum from (
    <select statement with order by clause>
  ) a where rownum <= MAX_ROW
) where rnum >= MIN_ROW

วิเคราะห์

select * from (
  <select statement with order by clause>
) where myrow between MIN_ROW and MAX_ROW

ทางเลือกสั้น ๆ

select * from (
  select statement, rownum as RN with order by clause
) where a.rn >= MIN_ROW and a.rn <= MAX_ROW

ผล

ตารางมี 10 ล้านเรคคอร์ดเรียงลำดับอยู่ในแถว datetime ที่ไม่ได้จัดทำดัชนี:

  • อธิบายแผนแสดงค่าเดียวกันสำหรับทั้งสามตัวเลือก (323168)
  • แต่ผู้ชนะคือ AskTom (โดยมีการวิเคราะห์ตามหลัง)

ทำการเลือก 10 แถวแรก:

  • AskTom: 28-30 วินาที
  • วิเคราะห์: 33-37 วินาที
  • ทางเลือกสั้น: 110-140 วินาที

การเลือกแถวระหว่าง 100,000 ถึง 100,010:

  • AskTom: 60 วินาที
  • วิเคราะห์: 100 วินาที

การเลือกแถวระหว่าง 9,000,000 ถึง 9,000,010:

  • AskTom: 130 วินาที
  • วิเคราะห์: 150 วินาที

ทำได้ดีมาก คุณลองใช้ทางเลือกสั้น ๆ โดยแทนที่ระหว่าง> = และ <= หรือไม่?
Mathieu Longtin

4
@MathieuLongtin BETWEENเป็นเพียงชื่อย่อสำหรับ>= AND <=( stackoverflow.com/questions/4809083/between-clause-versus-and )
wweicker

1
zeldi - นี่เป็นรุ่นอะไร? Oracle ได้ทำการปรับปรุงประสิทธิภาพการวิเคราะห์ใน 11.1 และ 11.2
Leigh Riffel

@ Leigh Riffel มันคือ 10.2.0.5; วันหนึ่งฉันอาจต้องใช้เวลาและตรวจสอบเวอร์ชั่น 11i ด้วย
zeldi

5
ฉันทำการทดสอบอย่างรวดเร็วและได้ผลลัพธ์ที่คล้ายกันสำหรับ 12c offsetไวยากรณ์ใหม่มีแผนและประสิทธิภาพเช่นเดียวกับวิธีการวิเคราะห์
Jon Heller

55

โซลูชันการวิเคราะห์ที่มีหนึ่งแบบสอบถามซ้อนกันเท่านั้น:

SELECT * FROM
(
   SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
) 
WHERE MyRow BETWEEN 10 AND 20;

Rank()อาจถูกแทนที่ด้วยRow_Number()แต่อาจส่งกลับระเบียนมากกว่าที่คุณคาดหวังหากมีค่าซ้ำกันสำหรับชื่อ


3
ฉันรักการวิเคราะห์ คุณอาจต้องการชี้แจงความแตกต่างของพฤติกรรมระหว่างอันดับ () และ Row_Number ()
Dave Costa

แน่นอนไม่แน่ใจว่าทำไมฉันไม่คิดซ้ำซ้อน ดังนั้นในกรณีนี้หากมีค่าซ้ำกันสำหรับชื่อ RANK สามารถให้ระเบียนมากกว่าที่คุณคาดหวังดังนั้นคุณควรใช้ Row_Number
Leigh Riffel

ถ้าพูดถึงrank()มันก็คุ้มค่าdense_rank()ที่จะสังเกตเห็นซึ่งอาจมีประโยชน์มากกว่าสำหรับการควบคุมเอาท์พุทขณะที่หลังไม่ได้ "ข้าม" หมายเลขขณะที่rank()สามารถ ในกรณีใด ๆ สำหรับคำถามrow_number()นี้เหมาะสมที่สุด อีกวิธีหนึ่งไม่ได้เป็นเทคนิคนี้ใช้ได้กับฐานข้อมูลใด ๆ ที่สนับสนุนฟังก์ชั่นที่กล่าวถึง
Used_By_Already

28

บน Oracle 12c (ดูข้อ จำกัด แถวในการอ้างอิง SQL ):

SELECT * 
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

53
และแน่นอนว่าพวกเขาต้องใช้ไวยากรณ์ที่แตกต่างอย่างสิ้นเชิงกว่าคนอื่น ๆ จนถึง
ทุกวันนี้

9
เห็นได้ชัดหลังจากนั่งลงกับผู้ขายอื่น ๆ ทั้งหมดเพื่อตกลงLIMITใน SQL: 2008 พวกเขาต้องเอาหนังสือของ Microsoft ออกและทำลายมาตรฐาน
beldaz

1
น่าสนใจที่ฉันได้ยินเมื่อเร็ว ๆ นี้ว่ามาตรฐานล่าสุดรวมถึงไวยากรณ์นี้ดังนั้น Oracle อาจผลักมันก่อนก่อนที่จะใช้ เนื้อหามีความยืดหยุ่นมากกว่าLIMIT ... OFFSET
beldaz

3
@ ดีเร็ก: ใช่การไม่ปฏิบัติตามมาตรฐานเป็นเรื่องน่าเศร้า แต่ฟังก์ชั่นที่เพิ่งเปิดตัวใน 12cR1 นั้นมีประสิทธิภาพมากกว่าเพียงแค่LIMIT n, m(ดูคำตอบของฉัน) จากนั้นอีกครั้ง, Oracle ควรมีการดำเนินการเป็นน้ำตาลประโยคมันเป็นเทียบเท่ากับLIMIT n, m OFFSET n ROWS FETCH NEXT m ROWS ONLY
sampathsris

10
@ ดีเร็ก: จริง ๆ แล้วฉันเพิ่งสังเกตคำพูดนี้ในคู่มือ PostgreSQL postgresql.org/docs/9.0/static/sql-select.html#AEN69535 "ข้อ จำกัด และ OFFS เป็นไวยากรณ์เฉพาะของ PostgreSQL ซึ่งใช้โดย MySQL ด้วยเช่นกัน SQL : 2008 มาตรฐานได้นำเสนอคำสั่ง OFFSET ... FETCH {FIRST | NEXT} ... สำหรับฟังก์ชันการทำงานเดียวกัน " ดังนั้น LIMIT จึงไม่เคยเป็นส่วนหนึ่งของมาตรฐาน
beldaz

14

การแบ่งหน้าแบบสอบถามด้วยการสั่งซื้อนั้นเป็นเรื่องยุ่งยากใน Oracle

Oracle จัดให้มีคอลัมน์ลับ ROWNUM ที่ส่งคืนตัวเลขซึ่งระบุลำดับที่ฐานข้อมูลเลือกแถวจากตารางหรือชุดของมุมมองที่เข้าร่วม

ROWNUM เป็นนามแฝงเทียมที่ทำให้คนจำนวนมากเดือดร้อน ค่า ROWNUM ไม่ได้ถูกกำหนดให้กับแถวอย่างถาวร (นี่เป็นความเข้าใจผิดทั่วไป) อาจเกิดความสับสนเมื่อกำหนดค่า ROWNUM จริง ค่า ROWNUM ได้รับมอบหมายให้แถวหลังจากที่มันผ่านภาคกรองของแบบสอบถาม แต่ก่อนที่จะรวมคำถามหรือการเรียงลำดับ

ยิ่งไปกว่านั้นค่า ROWNUM จะเพิ่มขึ้นหลังจากได้รับการกำหนดเท่านั้น

นี่คือสาเหตุที่คิวรี followin ไม่ส่งคืนแถว:

 select * 
 from (select *
       from some_table
       order by some_column)
 where ROWNUM <= 4 and ROWNUM > 1; 

แถวแรกของผลการค้นหาไม่ผ่าน ROWNUM> 1 เพรดิเคตดังนั้น ROWNUM จะไม่เพิ่มขึ้นเป็น 2 ด้วยเหตุนี้จึงไม่มีค่า ROWNUM มากกว่า 1 ดังนั้นแบบสอบถามจะไม่ส่งคืนแถว

ข้อความค้นหาที่กำหนดอย่างถูกต้องควรมีลักษณะดังนี้:

select *
from (select *, ROWNUM rnum
      from (select *
            from skijump_results
            order by points)
      where ROWNUM <= 4)
where rnum > 1; 

ค้นหาเพิ่มเติมเกี่ยวกับข้อความค้นหาการแบ่งหน้าในบทความของฉันบนบล็อกVertabelo :


2
แถวแรกของผลการสืบค้นไม่ผ่าน ROWNUM> 1 เพรดิเคต (…) - upvote เพื่ออธิบายสิ่งนี้
Piotr Dobrogost

6

มาตรฐาน SQL

ดังที่ฉันอธิบายไว้ในบทความนี้ SQL: 2008 Standard มีไวยากรณ์ต่อไปนี้เพื่อ จำกัด ชุดผลลัพธ์ SQL:

SELECT
    title
FROM
    post
ORDER BY
    id DESC
FETCH FIRST 50 ROWS ONLY

Oracle 11g และเวอร์ชันที่เก่ากว่า

ก่อนหน้าเวอร์ชัน 12c เพื่อดึงข้อมูลระเบียน Top-N คุณต้องใช้ตารางที่ได้รับและ pseudocolumn ROWNUM:

SELECT *
FROM (
    SELECT
        title
    FROM
        post
    ORDER BY
        id DESC
)
WHERE ROWNUM <= 50

5

คำสั่ง SELECT น้อยลง นอกจากนี้ยังกินประสิทธิภาพน้อยลง เครดิตไปที่: anibal@upf.br

SELECT *
    FROM   (SELECT t.*,
                   rownum AS rn
            FROM   shhospede t) a
    WHERE  a.rn >= in_first
    AND    a.rn <= in_first;

2
นอกจากนี้ยังเป็นคำตอบที่ไม่ถูกต้องทั้งหมด คำถามเกี่ยวกับการ จำกัด หลังจากการเรียงลำดับ ดังนั้น rownum ควรอยู่นอกเคียวรี
BitLord

5

เป็นส่วนขยายของคำตอบที่ยอมรับ Oracle ใช้ROW_NUMBER/RANKฟังก์ชันภายใน OFFSET FETCHไวยากรณ์เป็นไวยากรณ์น้ำตาล

มันสามารถสังเกตได้โดยใช้DBMS_UTILITY.EXPAND_SQL_TEXTขั้นตอน:

เตรียมตัวอย่าง:

CREATE TABLE rownum_order_test (
  val  NUMBER
);

INSERT ALL
  INTO rownum_order_test
SELECT level
FROM   dual
CONNECT BY level <= 10;
COMMIT;

ค้นหา:

SELECT val
FROM   rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY;

เป็นปกติ:

SELECT "A1"."VAL" "VAL" 
FROM  (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
               ROW_NUMBER() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rownumber" 
      FROM "ROWNUM_ORDER_TEST" "A2") "A1" 
WHERE "A1"."rowlimit_$$_rownumber"<=5 ORDER BY "A1"."rowlimit_$_0" DESC;

db <> การสาธิตซอ

การดึงข้อความ SQL แบบขยาย:

declare
  x VARCHAR2(1000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => '
          SELECT val
          FROM   rownum_order_test
          ORDER BY val DESC
          FETCH FIRST 5 ROWS ONLY',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/

WITH TIESถูกขยายเมื่อRANK:

declare
  x VARCHAR2(1000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => '
          SELECT val
          FROM   rownum_order_test
          ORDER BY val DESC
          FETCH FIRST 5 ROWS WITH TIES',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/

SELECT "A1"."VAL" "VAL" 
FROM  (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
              RANK() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rank" 
       FROM "ROWNUM_ORDER_TEST" "A2") "A1" 
WHERE "A1"."rowlimit_$$_rank"<=5 ORDER BY "A1"."rowlimit_$_0" DESC

และชดเชย:

declare
  x VARCHAR2(1000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => '
          SELECT val
FROM   rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/


SELECT "A1"."VAL" "VAL" 
FROM  (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
             ROW_NUMBER() OVER ( ORDER BY "A2"."VAL") "rowlimit_$$_rownumber" 
       FROM "ROWNUM_ORDER_TEST" "A2") "A1" 
       WHERE "A1"."rowlimit_$$_rownumber"<=CASE  WHEN (4>=0) THEN FLOOR(TO_NUMBER(4)) 
             ELSE 0 END +4 AND "A1"."rowlimit_$$_rownumber">4 
ORDER BY "A1"."rowlimit_$_0"

3

หากคุณไม่ได้อยู่ใน Oracle 12C คุณสามารถใช้การสืบค้น TOP N เช่นด้านล่าง

SELECT *
 FROM
   ( SELECT rownum rnum
          , a.*
       FROM sometable a 
   ORDER BY name
   )
WHERE rnum BETWEEN 10 AND 20;

คุณสามารถย้ายสิ่งนี้จากส่วนคำสั่งด้วย clause ดังนี้

WITH b AS
( SELECT rownum rnum
      , a.* 
   FROM sometable a ORDER BY name
) 
SELECT * FROM b 
WHERE rnum BETWEEN 10 AND 20;

ที่นี่เรากำลังสร้างมุมมองแบบอินไลน์และเปลี่ยนชื่อ rownum เป็น rnum คุณสามารถใช้ rnum ในแบบสอบถามหลักเป็นเกณฑ์ตัวกรอง


1
ในกรณีของฉันนี่ไม่ได้ส่งคืนแถวที่ถูกต้อง สิ่งที่ฉันทำเพื่อแก้ไขคือทำORDER BYและrownumแยกกัน โดยทั่วไปฉันสร้างแบบสอบถามย่อยที่มีORDER BYข้อ
Patrick Gregorio

ลงคะแนนเนื่องจากเป็นคำตอบที่ไม่ถูกต้อง คำถามเกี่ยวกับการ จำกัด หลังจากการเรียงลำดับดังนั้นrownumควรอยู่นอกแบบสอบถามย่อย
Piotr Dobrogost

@PiotrDobrogost rownum อยู่นอกเท่านั้น
sandi

2

ฉันได้เริ่มเตรียมการสำหรับ Oracle 1z0 - 047 สอบตรวจสอบกับ 12c ในขณะที่เตรียมมันฉันเจอการปรับปรุง 12c ที่เรียกว่า 'FETCH FIRST' ช่วยให้คุณสามารถดึงแถว / แถวที่ จำกัด ได้ตามความสะดวกของคุณ มีหลายตัวเลือกให้เลือก

- FETCH FIRST n ROWS ONLY
 - OFFSET n ROWS FETCH NEXT N1 ROWS ONLY // leave the n rows and display next N1 rows
 - n % rows via FETCH FIRST N PERCENT ROWS ONLY

ตัวอย่าง:

Select * from XYZ a
order by a.pqr
FETCH FIRST 10 ROWS ONLY

3
stackoverflow.com/a/26051830/635608 - คำตอบนี้มีให้ในคำตอบอื่น ๆ แล้ว โปรดงดเว้นการโพสต์เนื้อหาที่โพสต์แล้วเมื่อหลายเดือนก่อน
Mat

1
โอ้แน่ใจว่าไม่ได้ตอบทุกคำตอบฉันเจอคำถามย่อยก่อนหน้านี้จะจำไว้
arjun gaur

1
select * FROM (SELECT 
   ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, 
 FROM EMP ) EMP  where ROWID=5

มากขึ้นแล้วหาค่า

select * FROM (SELECT 
       ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, 
     FROM EMP ) EMP  where ROWID>5

หาค่าน้อยกว่า

select * FROM (SELECT 
       ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID, 
     FROM EMP ) EMP  where ROWID=5

Downvote เป็นROW_NUMBER()โซลูชันพื้นฐานที่โพสต์แล้วโดย Leigh Riffel ในการติดมีข้อผิดพลาดทางไวยากรณ์ในรหัสที่แสดง
Piotr Dobrogost

1

สำหรับแต่ละแถวที่ส่งคืนโดยเคียวรี ROWNUM pseudocolumn จะส่งคืนตัวเลขที่ระบุลำดับที่ Oracle เลือกแถวจากตารางหรือชุดของแถวที่เข้าร่วม แถวแรกที่เลือกมี ROWNUM เป็น 1 และแถวที่สองมี 2 และอื่น ๆ

  SELECT * FROM sometable1 so
    WHERE so.id IN (
    SELECT so2.id from sometable2 so2
    WHERE ROWNUM <=5
    )
    AND ORDER BY so.somefield AND ROWNUM <= 100 

ฉันใช้สิ่งนี้ในoracleเซิร์ฟเวอร์11.2.0.1.0


downvote เป็นคำถามที่ถามเกี่ยวกับการ จำกัดแถวที่สั่งและคุณยังไม่มีคำสั่ง
Piotr Dobrogost

@PiotrDobrogost เข้าใจว่าไม่ใช่เรื่องใหญ่การสั่งซื้อคีย์เวิร์ดเป็นเรื่องธรรมดาสำหรับ rdbms ทั้งหมดที่ จำกัด เท่านั้นที่มีการเปลี่ยนแปลง
Sumesh TG

-1

ในกรณีของ SQL-Developer จะดึงข้อมูลเฉพาะ 50 แถวแรกโดยอัตโนมัติ และถ้าเราเลื่อนลงมันจะดึงแถวอีก 50 แถวขึ้นไปเรื่อย ๆ !

ดังนั้นเราไม่จำเป็นต้องกำหนดในกรณีของเครื่องมือนักพัฒนา sql!


-3

ใน oracle

SELECT val FROM   rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY;

VAL

    10
    10
     9
     9
     8

เลือก 5 แถว

SQL>


7
คุณควรระบุว่าสิ่งนี้มีผลบังคับใช้ตั้งแต่ Oracle 12c และคัดลอก / วางจากที่อื่น - โปรดอ้างอิงแหล่งข้อมูลของคุณเสมอ
Mat

แหล่งที่มานี้ @Mat และ Rakesh โปรดลองอย่างน้อยที่สุดเพื่อปรับคำตอบสำหรับคำถามเดิม ฉันยังได้ให้คำตอบที่อ้างถึงแหล่งเดียวกัน แต่ฉันพยายามที่จะครอบคลุมและอ้างถึงแหล่งต้นฉบับ
sampathsris

-4

(ยังไม่ทดลอง) บางอย่างเช่นนี้อาจทำงานได้

WITH
base AS
(
    select *                   -- get the table
    from sometable
    order by name              -- in the desired order
),
twenty AS
(
    select *                   -- get the first 30 rows
    from base
    where rownum < 30
    order by name              -- in the desired order
)
select *                       -- then get rows 21 .. 30
from twenty
where rownum > 20
order by name                  -- in the desired order

นอกจากนี้ยังมีฟังก์ชันอันดับการวิเคราะห์ที่คุณสามารถใช้ในการสั่งซื้อ


2
สิ่งนี้จะไม่ส่งคืนแถวเดียวเนื่องจาก ROWNUM เป็นคอลัมน์ในชุดผลลัพธ์ดังนั้นเงื่อนไข WHERE สุดท้ายจะเป็นเท็จเสมอ นอกจากนี้คุณไม่สามารถใช้ ROWNUM และคำสั่งซื้อโดย ORDER รับประกัน
Ben

2
ยอดเยี่ยม ปล่อยให้นี่เป็นคำเตือนให้คนอื่น
EvilTeach

-5

เช่นเดียวกับการแก้ไขข้างต้น ใช้งานได้ แต่ไม่สวยแน่นอน

   WITH
    base AS
    (
        select *                   -- get the table
        from sometable
        order by name              -- in the desired order
    ),
    twenty AS
    (
        select *                   -- get the first 30 rows
        from base
        where rownum <= 30
        order by name              -- in the desired order
    )
    select *                       -- then get rows 21 .. 30
    from twenty
    where rownum < 20
    order by name                  -- in the desired order

สุจริตดีกว่าที่จะใช้คำตอบข้างต้น


5
สิ่งนี้ไม่ถูกต้องเนื่องจากคำสั่ง WHERE ถูกประเมินก่อน ORDER BY
เบ็น

3
ขโมยที่น่าสนใจจากคำตอบที่ไม่ดีของฉันด้านล่าง
EvilTeach
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.