จะเลือกเพียง 1 แถวจาก oracle sql ได้อย่างไร


113

ฉันต้องการใช้ไวยากรณ์ oracle เพื่อเลือกเพียง 1 แถวจากตาราง DUALแถวจากตาราง ตัวอย่างเช่นฉันต้องการดำเนินการค้นหานี้:

SELECT user 
  FROM DUAL

... และมันจะมี 40 รายการ แต่ฉันต้องการเพียงบันทึกเดียว ... และฉันต้องการให้มันเกิดขึ้นโดยไม่มีWHEREข้อ

ฉันต้องการบางสิ่งในฟิลด์ table_name เช่น:

SELECT FirstRow(user) 
  FROM DUAL

1
Oracle เวอร์ชันใด การใช้ ROWNUM หรือ ROW_NUMBER (9i +) หมายความว่าต้องการคำสั่ง WHERE
OMG Ponies

1
ตั้งชื่อโต๊ะdualหรือเปล่า
ypercubeᵀᴹ

1
@ypercube dualเป็นตารางระบบใน oracle

4
@ Ben DUALคุณจริงๆไม่ควรสร้างตารางที่เรียกว่า มันเหมือนกับ#define TRUE 0ใน C - แน่นอนว่ามันอาจใช้ได้กับคุณ แต่นักพัฒนาในอนาคตจะเกลียดคุณ
Jeffrey Kemp

3
ได้ลองวิ่งจริงselect user from dualหรือ? ถ้าไม่ลองดูว่าคุณจะได้อะไร ในระบบ oracle มาตรฐานคุณจะได้รับคืนผู้ใช้ที่คุณกำลังเรียกใช้คำสั่งด้วย
Shannon Severance

คำตอบ:


171

คุณใช้ ROWNUM

กล่าวคือ.

SELECT user FROM Dual WHERE ROWNUM = 1

http://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns009.htm


@ypercube เท่าที่ฉันบอกได้มันทำ (อย่างน้อยก็ใช้ได้กับการติดตั้ง oracle10g ของฉัน)

@bdares: มันจะได้ผลใช่ แต่ไม่ใช่คำตอบของคุณกับorder by.
ypercubeᵀᴹ

1
ใช่. ROWNUM เป็นคอลัมน์พิเศษที่เพิ่มเข้าไปในชุดผลลัพธ์ที่แจกแจงผลลัพธ์ คุณสามารถใช้เพื่อเลือกหลาย ๆ คนได้เช่นกันตัวอย่างเช่นหากคุณต้องการค้นหาพนักงานที่ได้รับค่าตอบแทนสูงสุด 10 คนคุณอาจพูดว่า "เลือกผู้ใช้จากพนักงาน WHERE ROWNUM <= 10 ORDER BY SALARY DESCENDING"
mindvirus

10
@mkdess: ไม่ORDER BYใช้หลังจากWHERE.
ypercubeᵀᴹ

15
คุณต้องการ:SELECT * FROM (SELECT user FROM Employees ORDER BY SALARY DESC) WHERE ROWNUM <= 10
ypercubeᵀᴹ

50

ฉันพบ "วิธีแก้ปัญหา" นี้ซ่อนอยู่ในหนึ่งในความคิดเห็น เนื่องจากฉันค้นหามันมาระยะหนึ่งแล้วฉันจึงต้องการเน้นมันสักหน่อย (ยังไม่สามารถแสดงความคิดเห็นหรือทำสิ่งนั้นได้ ... ) นี่คือสิ่งที่ฉันใช้:

SELECT * FROM (SELECT [Column] FROM [Table] ORDER BY [Date] DESC) WHERE ROWNUM = 1

นี่จะพิมพ์รายการ [คอลัมน์] ที่ต้องการจากรายการล่าสุดในตารางโดยสมมติว่า [วันที่] ถูกแทรกผ่าน SYSDATE เสมอ


ฉันพบว่ามันจะใช้งานได้เช่นกันหากคุณสั่งซื้อROWIDตราบเท่าที่คุณไม่เคยลบบันทึกใด ๆ และให้ความสำคัญกับการแทรก / แก้ไขล่าสุดเสมอ
vapcguy

@vapcguy: อย่าคาดหวังว่าจะได้รับคำสั่ง ROWID แม้ว่าคุณจะไม่เคยลบแถวออกจากตารางก็ตาม! แม้ว่าตอนนี้จะเหมาะกับคุณ แต่ก็ไม่รับประกันว่าจะใช้งานได้ในเวอร์ชันอนาคต
D. Mika

@ D.Mika จริงๆแล้วถ้าตอนนี้ใช้งานได้และคุณไม่เคยเพิ่ม / ลบ / อัปเดต / ลบบันทึกก็ไม่น่าจะมีปัญหาใด ๆ ระเบียนสามารถเปลี่ยนแปลงได้ก็ต่อเมื่อคุณเปลี่ยนแปลงจริง มีความเข้าใจผิดว่าROWIDOracle แก้ไขแบบสุ่ม มันไม่ใช่ มันขึ้นอยู่กับการปรับเปลี่ยนแถวจริง ๆ นั่นคือคุณลบหนึ่งแถวแล้วแทรกหนึ่งแถว ROWIDแทรกหนึ่งจะได้รับเก่าหนึ่งของ มีสิ่งต่างๆเช่นตารางคงที่ที่ไม่เคยได้รับสถานะเหมือนการอัปเดตในสหรัฐอเมริกาเป็นตัวอย่างที่ดีซึ่งหากมีการเปลี่ยนแปลงก็อาจมีผลกระทบอื่น ๆ อยู่ดีเมื่อเป็นเช่นนั้น
vapcguy

@vapcguy: อืมเกือบถูกแล้ว แต่มีการดำเนินการอื่น ๆ ที่จะเปลี่ยน ROWID จะเกิดอะไรขึ้นถ้าคุณส่งออก / นำเข้าตารางด้วยเหตุผลบางประการ? มีการดำเนินการอื่น ๆ แต่บางส่วนจำเป็นต้องเปิดใช้งานการเคลื่อนย้ายแถว ฉันแค่อยากจะบอกว่าไม่ควรพึ่งพารายละเอียดการใช้งานที่อาจเปลี่ยนแปลงในอนาคต
D. Mika

@ D.Mika ฉันแน่ใจว่ามีการดำเนินการใด ๆ ที่ROWIDสามารถเปลี่ยนแปลงได้ DBA ที่ดีจะค้นหาและทำในสิ่งที่ทำได้เพื่อหลีกเลี่ยงหากมีความเป็นไปได้ที่จะส่งผลกระทบต่อตารางคงที่ดังที่ฉันอธิบายไว้ ควรเปิดใช้งานแอปพลิเคชันเท่านั้น การส่งออกตารางสามารถทำได้โดยใช้SELECTคำสั่งแทน การนำเข้าจะเกิดขึ้นครั้งแล้วครั้งเล่า ฉันเข้าใจว่าคุณต้องการการดูแลเป็นอย่างดี แต่ปัญหาก็ยังห่างไกลจากสิ่งที่หลีกเลี่ยงไม่ได้
vapcguy

35

ไวยากรณ์นี้มีอยู่ใน Oracle 12c:

select * from some_table fetch first 1 row only;
select * from some_table fetch first 1 rows only;
select * from some_table fetch first 10 row only;
select * from some_table fetch first 10 rows only;

^^ ฉันแค่อยากจะสาธิตว่าสามารถใช้ row หรือ row (พหูพจน์) ได้โดยไม่คำนึงถึงจำนวนแถวที่ต้องการ)


1
เลือก * จาก some_table ดึงข้อมูล 1 แถวแรกเท่านั้น มันไม่ทำงานใน swl devloper ของฉันหรือใน sql บวกดังนั้นจึงเกิดข้อผิดพลาดในการดึงข้อมูล
nikhil sugandh

คุณใช้ oracle 12c หรือไม่?
mancini0

ฉันไม่รู้จริงๆ แต่เมื่อฉันเปิดมันแสดงแบบนี้: SQL * PLus Release 10.1.0.4.2 ไม่ใช่ 12 c หรือไม่
nikhil sugandh

ถูกต้อง - คุณน่าจะใช้เวอร์ชัน 10.1.xxx คุณสามารถเลือก * จาก V $ VERSION
mancini0

11

เรามี 3 ทางเลือกในการรับแถวแรกในตาราง Oracle DB

1) select * from table_name where rownum= 1เป็นวิธีที่ดีที่สุด

2) select * from table_name where id = ( select min(id) from table_name)

3)

select * from 
    (select * from table_name order by id)
where rownum = 1

ขอบคุณสำหรับคำตอบ: ภายใต้จุดที่ 3) "nowrum = 1" น่าจะเปลี่ยนเป็น "rownum = 1"
Andre Nel

7

เท่าที่ฉันรู้dualตารางใน Oracle เป็นตารางพิเศษที่มีเพียงแถวเดียว ดังนั้นสิ่งนี้ก็เพียงพอแล้ว:

SELECT user
FROM dual

นั่นไม่ใช่ผู้ใช้ที่เลือกจริงจาก dual ควรให้ผู้ใช้ทั้งหมดแก่คุณ
เบ็


1
.. และเพิ่งทดลองใช้กับระบบของฉันทำงานเป็น ypercube และเอกสารที่เกี่ยวข้องทั้งหมดกล่าวถึง @ Ben
Sathyajith Bhat

1
@Ben dual ไม่ใช่มุมมองแค็ตตาล็อก แต่จะไม่แสดง "ผู้ใช้ทั้งหมด" คุณจะใช้มุมมองเช่น ALL_USERS เพื่อจุดประสงค์นั้น
makrom

7

👌คำตอบคือ:

คุณควรใช้แบบสอบถามที่ซ้อนกันเป็น:

SELECT *
FROM ANY_TABLE_X 
WHERE ANY_COLUMN_X = (SELECT MAX(ANY_COLUMN_X) FROM ANY_TABLE_X) 

=> ใน PL / SQL "ROWNUM = 1" ไม่เท่ากับ "TOP 1" ของ TSQL

ดังนั้นคุณจึงไม่สามารถใช้คำค้นหาเช่นนี้: "select * from any_table_x โดย rownum = 1 order by any_column_x;" เนื่องจาก oracle ได้รับแถวแรกจึงใช้ลำดับตามอนุประโยค


1
โปรดเพิ่มคำชี้แจงให้กับคำตอบของคุณ
hgwhittle

ควรหลีกเลี่ยงไวยากรณ์ที่ผิดปกติโดยไม่มีเหตุผลที่ดี ในกรณีนี้การระบุกรณีทดสอบหรือหมายเลขข้อบกพร่องจะเป็นประโยชน์ ฉันจำปัญหาแปลก ๆ บางอย่างได้อย่างคลุมเครือrownum = 1แต่เราไม่ควรปล่อยให้บั๊กเก่าส่งผลกระทบต่อโค้ดของเราอีกต่อไป
Jon Heller

7
@hgwhittle เหตุผลที่ Fuat ถูกต้องก็เพราะว่า ROWNUM ไม่สนใจเรื่อง "ordery by" เพียงแค่คว้าบันทึกแรกที่สามารถค้นหาได้และส่งคืนทันที กล่าวอีกนัยหนึ่งคุณสมบัติ ROWNUM ไม่มีส่วนเกี่ยวข้องกับคำสั่ง "Order By" ฉันหวังว่าจะไม่เป็นเช่นนั้น แต่ Fuat ถูกต้องเพื่อใช้แบบสอบถามที่ซ้อนกัน
Eric Milliot-Martinez


5

"FirstRow" เป็นข้อ จำกัด และด้วยเหตุนี้จึงอยู่ในส่วนwhereคำสั่งที่ไม่อยู่ในselectอนุประโยค และเรียกว่า rownum

select * from dual where rownum = 1;

1
โปรดทราบว่าสิ่งนี้จะไม่ทำงานตามที่คาดไว้เมื่อใช้ร่วมกับORDER BYเนื่องจากการสั่งซื้อจะเกิดขึ้นหลังจากคำสั่ง where เท่านั้น กล่าวอีกนัยหนึ่งคือเพื่อให้ได้อันดับต้น ๆ ของข้อความค้นหาที่เรียงลำดับ rownum นั้นไร้ประโยชน์อย่างที่สุด
Nyerguds

@Nyerguds นี่เป็นความจริงเพียงครึ่งเดียว คุณสามารถใช้คำสั่งก่อนหน้าWhereด้วยแบบสอบถาม View
gdoron สนับสนุน Monica

4
อะไรนะSELECT * FROM (SELECT * FROM ... WHERE ... ORDER BY ...) WHERE ROWNUM = 1? นั่นอาจใช้งานได้ แต่มันดูโง่มาก
Nyerguds

2

หากมีแถวใดที่จะทำได้ลอง:

select max(user)  
from table;

ไม่มีประโยคที่ไหน


9
แน่นอนว่าจะใช้เวลาเพียงไม่กี่วินาทีในการลองด้วยตัวคุณเอง
Matt Donnan


1

select a.user from (select user from users order by user) a where rownum = 1

จะทำงานได้ดีที่สุดอีกทางเลือกหนึ่งคือ:

select a.user 
from ( 
select user, 
row_number() over (order by user) user_rank, 
row_number() over (partition by dept order by user) user_dept_rank 
from users 
) a 
where a.user_rank = 1 or user_dept_rank = 2

ในสถานการณ์ที่คุณต้องการชุดย่อยที่แตกต่างกัน แต่ฉันเดาว่าคุณสามารถใช้RANK()แต่ฉันก็ชอบเช่นกันrow_number() over(...)เนื่องจากไม่จำเป็นต้องมีการจัดกลุ่ม


0

หากคุณต้องการกลับมาเฉพาะแถวแรกของผลลัพธ์ที่เรียงลำดับโดยมีเคียวรีย่อยน้อยที่สุดให้ลองทำดังนี้:

select *
  from ( select a.*
              , row_number() over ( order by sysdate_col desc ) as row_num
           from table_name a )
  where row_num = 1;

โดยที่ sysdate_col จะเป็นชื่อของคอลัมน์ใด ๆ ที่คุณต้องการจัดเรียงและแน่นอน table_name จะเป็นชื่อของตารางที่คุณต้องการให้ข้อมูลที่เรียงลำดับมา
Jody Fedor

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