ฉันสามารถทำ SELECT TOP (200) ... แต่ทำไมไม่ BOTTOM (200) ล่ะ?
เพื่อไม่ให้เข้าใจถึงปรัชญาที่ฉันหมายถึงคือฉันจะทำอย่างไรให้เทียบเท่ากับ TOP (200) แต่ในทางกลับกัน (จากด้านล่างเช่นที่คุณคาดหวังให้ BOTTOM ทำ ... )
ฉันสามารถทำ SELECT TOP (200) ... แต่ทำไมไม่ BOTTOM (200) ล่ะ?
เพื่อไม่ให้เข้าใจถึงปรัชญาที่ฉันหมายถึงคือฉันจะทำอย่างไรให้เทียบเท่ากับ TOP (200) แต่ในทางกลับกัน (จากด้านล่างเช่นที่คุณคาดหวังให้ BOTTOM ทำ ... )
คำตอบ:
SELECT
columns
FROM
(
SELECT TOP 200
columns
FROM
My_Table
ORDER BY
a_column DESC
) SQ
ORDER BY
a_column ASC
มันไม่จำเป็น คุณสามารถใช้ORDER BY
และเพียงแค่เปลี่ยนการจัดเรียงเพื่อDESC
ให้ได้เอฟเฟกต์เดียวกัน
ขออภัยฉันคิดว่าฉันไม่เห็นคำตอบที่ถูกต้องในความคิดของฉัน
TOP
ฟังก์ชั่น x แสดงระเบียนในการสั่งซื้อไม่ได้กำหนด จากนิยามดังกล่าวBOTTOM
ทำให้ไม่สามารถกำหนดฟังก์ชันได้
ไม่ขึ้นอยู่กับดัชนีหรือลำดับการจัดเรียงใด ๆ เมื่อคุณทำORDER BY y DESC
คุณจะได้แถวที่มีค่า y สูงสุดก่อน หากนี่เป็นรหัสที่สร้างขึ้นโดยอัตโนมัติควรแสดงระเบียนที่เพิ่มลงในตารางล่าสุดตามที่แนะนำในคำตอบอื่น ๆ อย่างไรก็ตาม:
TOP
ฟังก์ชันคำตอบที่ถูกต้องควรเป็นไม่มีและไม่สามารถเทียบเท่ากับTOP
การรับแถวล่างสุด
ตามเหตุผล
BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n
เช่นเลือก 1000 อันดับสุดท้ายจากพนักงาน:
ใน T-SQL
DECLARE
@bottom int,
@count int
SET @bottom = 1000
SET @count = (select COUNT(*) from Employee)
select * from Employee emp where emp.EmployeeID not in
(
SELECT TOP (@count-@bottom) Employee.EmployeeID FROM Employee
)
ดูเหมือนว่าคำตอบใด ๆ ที่ใช้คำสั่ง ORDER BY ในการแก้ปัญหานั้นขาดประเด็นหรือไม่เข้าใจว่า TOP ส่งคืนอะไรให้คุณ
TOP ส่งคืนชุดผลลัพธ์แบบสอบถามที่ไม่เรียงลำดับซึ่ง จำกัด ระเบียนที่ตั้งไว้ที่ระเบียน N แรกที่ส่งคืน (จากมุมมองของ Oracle จะคล้ายกับการเพิ่มโดยที่ ROWNUM <(N + 1)
โซลูชันใด ๆ ที่ใช้คำสั่งอาจส่งคืนแถวที่ส่งคืนโดยส่วนคำสั่ง TOP (เนื่องจากชุดข้อมูลนั้นไม่ได้เรียงลำดับตั้งแต่แรก) ขึ้นอยู่กับเกณฑ์ที่ใช้ในการเรียงลำดับโดย
ประโยชน์ของ TOP คือเมื่อชุดข้อมูลถึงขนาดที่กำหนด N จะหยุดดึงข้อมูลแถว คุณจะรู้สึกได้ว่าข้อมูลมีลักษณะอย่างไรโดยไม่ต้องดึงข้อมูลทั้งหมด
ในการใช้งาน BOTTOM อย่างถูกต้องจะต้องดึงชุดข้อมูลทั้งหมดที่ไม่ได้เรียงลำดับจากนั้นจึง จำกัด ชุดข้อมูลไว้ที่ระเบียน N สุดท้าย สิ่งนี้จะไม่ได้ผลเป็นพิเศษหากคุณกำลังจัดการกับโต๊ะขนาดใหญ่ ไม่จำเป็นต้องให้สิ่งที่คุณคิดว่าคุณกำลังขอ ส่วนท้ายของชุดข้อมูลอาจไม่จำเป็นต้องเป็น "แถวสุดท้ายที่แทรก" (และอาจไม่เหมาะสำหรับแอปพลิเคชันที่เน้น DML ส่วนใหญ่)
ในทำนองเดียวกันโซลูชันที่ใช้ ORDER BY นั้นน่าเสียดายที่อาจเป็นหายนะเมื่อต้องจัดการกับชุดข้อมูลขนาดใหญ่ ถ้าฉันมีบอกว่า 10 พันล้านเรกคอร์ดและต้องการ 10 คนสุดท้ายมันค่อนข้างโง่ที่จะสั่งซื้อ 10 พันล้านเรกคอร์ดและเลือก 10 รายการสุดท้าย
ปัญหาตรงนี้คือ BOTTOM ไม่ได้มีความหมายอย่างที่เราคิดเมื่อเปรียบเทียบกับ TOP
เมื่อบันทึกถูกแทรกลบแทรกลบซ้ำแล้วซ้ำอีกช่องว่างบางส่วนจะปรากฏในที่จัดเก็บข้อมูลและในภายหลังแถวจะถูก slotted ถ้าเป็นไปได้ แต่สิ่งที่เรามักจะเห็นเมื่อเราเลือก TOP ดูเหมือนจะเป็นการจัดเรียงข้อมูลเนื่องจากอาจถูกแทรกในช่วงต้นของการมีอยู่ของตาราง หากตารางไม่พบการลบหลายครั้งอาจดูเหมือนว่ามีการสั่งซื้อ (เช่นวันที่สร้างอาจย้อนเวลากลับไปได้ไกลพอ ๆ กับการสร้างตารางเอง) แต่ความจริงก็คือถ้านี่เป็นตารางที่มีการลบมากแถว TOP N อาจไม่เป็นเช่นนั้นเลย
ดังนั้น - สิ่งที่สำคัญที่สุดที่นี่ (ตั้งใจให้เล่นสำนวน) คือคนที่ขอบันทึก BOTTOM N ไม่รู้จริง ๆ ว่าพวกเขากำลังขออะไร หรืออย่างน้อยที่สุดสิ่งที่พวกเขาขอและความหมายของ BOTTOM นั้นไม่ใช่สิ่งเดียวกัน
ดังนั้น - การแก้ปัญหาอาจตอบสนองความต้องการทางธุรกิจที่แท้จริงของผู้ร้องขอ ... แต่ไม่ตรงตามเกณฑ์สำหรับการเป็น BOTTOM
insert
คำสั่งขนาดใหญ่เพื่อใส่แถวลงในตารางขนาดใหญ่ที่ไม่ได้จัดทำดัชนี (ฉันกำลังเติมข้อมูลในตารางก่อนที่จะเริ่มสร้างดัชนี) ฉันสูญเสียเซสชันไคลเอ็นต์ของฉันเนื่องจากการรีบูตหรืออะไรก็ตามและตอนนี้ฉันต้องการดูว่ามีแถวที่เพิ่มเข้ามาใหม่หรือไม่ ถ้าแถว 'ล่าง' ของตารางเป็นแถวล่าสุดของฉันฉันรู้ว่าการดำเนินการเสร็จสมบูรณ์ ถ้าแถว 'ด้านล่าง' เป็นอย่างอื่นก็ไม่มีการรับประกันใด ๆ และฉันต้องสแกนทั้งตารางเพื่อให้แน่ใจ ... แต่ส่วนใหญ่แล้วฉันสามารถประหยัดเวลาได้โดยการตรวจสอบ 'ด้านล่าง' อย่างรวดเร็วเช่นเดียวกับที่คุณสามารถ ' ด้านบน '.
คำตอบที่ "จัสตินเอเทียร์" ยอมรับในปัจจุบันไม่ใช่คำตอบที่ถูกต้องตามที่ "ผู้พิทักษ์วัน" ชี้ไว้
เท่าที่ฉันเห็น ณ ตอนนี้ไม่มีคำตอบหรือความคิดเห็นอื่นใดที่เทียบเท่ากับ BOTTOM (x) ที่ผู้เขียนถาม
ขั้นแรกให้พิจารณาสถานการณ์ที่จำเป็นต้องใช้ฟังก์ชันนี้:
SELECT * FROM Split('apple,orange,banana,apple,lime',',')
สิ่งนี้ส่งคืนตารางหนึ่งคอลัมน์และห้าระเบียน:
ดังที่คุณเห็น: เราไม่มีคอลัมน์ ID; เราไม่สามารถสั่งซื้อตามคอลัมน์ที่ส่งคืนได้ และเราไม่สามารถเลือกสองระเบียนล่างโดยใช้ SQL มาตรฐานเหมือนกับที่เราสามารถทำได้สำหรับสองระเบียนแรก
นี่คือความพยายามของฉันที่จะหาทางแก้ไข:
SELECT * INTO #mytemptable FROM Split('apple,orange,banana,apple,lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
SELECT TOP 2 * FROM #mytemptable ORDER BY tempID DESC
DROP TABLE #mytemptable
และนี่คือโซลูชันที่สมบูรณ์ยิ่งขึ้น:
SELECT * INTO #mytemptable FROM Split('apple,orange,banana,apple,lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
DELETE FROM #mytemptable WHERE tempID <= ((SELECT COUNT(*) FROM #mytemptable) - 2)
ALTER TABLE #mytemptable DROP COLUMN tempID
SELECT * FROM #mytemptable
DROP TABLE #mytemptable
ฉันไม่ได้อ้างว่านี่เป็นความคิดที่ดีที่จะใช้ในทุกสถานการณ์ แต่ให้ผลลัพธ์ที่ต้องการ
สิ่งที่คุณต้องทำคือย้อนกลับORDER BY
ไฟล์. เพิ่มหรือลบDESC
มัน
ปัญหาในการสั่งซื้ออีกทางหนึ่งก็คือมักใช้ดัชนีไม่ได้ผล นอกจากนี้ยังไม่สามารถขยายได้มากนักหากคุณจำเป็นต้องเลือกแถวจำนวนหนึ่งที่ไม่ได้อยู่ที่จุดเริ่มต้นหรือจุดสิ้นสุด ทางเลือกมีดังนี้
DECLARE @NumberOfRows int;
SET @NumberOfRows = (SELECT COUNT(*) FROM TheTable);
SELECT col1, col2,...
FROM (
SELECT col1, col2,..., ROW_NUMBER() OVER (ORDER BY col1) AS intRow
FROM TheTable
) AS T
WHERE intRow > @NumberOfRows - 20;
คำตอบ "Tom H" ด้านบนถูกต้องและเหมาะกับฉันในการรับแถว 5 ล่างสุด
SELECT [KeyCol1], [KeyCol2], [Col3]
FROM
(SELECT TOP 5 [KeyCol1],
[KeyCol2],
[Col3]
FROM [dbo].[table_name]
ORDER BY [KeyCol1],[KeyCol2] DESC) SOME_ALAIS
ORDER BY [KeyCol1],[KeyCol2] ASC
ขอบคุณ.
ลองดู
declare @floor int --this is the offset from the bottom, the number of results to exclude
declare @resultLimit int --the number of results actually retrieved for use
declare @total int --just adds them up, the total number of results fetched initially
--following is for gathering top 60 results total, then getting rid of top 50. We only keep the last 10
set @floor = 50
set @resultLimit = 10
set @total = @floor + @resultLimit
declare @tmp0 table(
--table body
)
declare @tmp1 table(
--table body
)
--this line will drop the wanted results from whatever table we're selecting from
insert into @tmp0
select Top @total --what to select (the where, from, etc)
--using floor, insert the part we don't want into the second tmp table
insert into @tmp1
select top @floor * from @tmp0
--using select except, exclude top x results from the query
select * from @tmp0
except
select * from @tmp1
ฉันได้หาวิธีแก้ปัญหานี้ที่ไม่ต้องการให้คุณทราบจำนวนแถวที่ส่งคืน
ตัวอย่างเช่นหากคุณต้องการรับตำแหน่งทั้งหมดที่บันทึกไว้ในตารางยกเว้น 1 (หรือ 2 หรือ 5 หรือ 34) ล่าสุด
SELECT *
FROM
(SELECT ROW_NUMBER() OVER (ORDER BY CreatedDate) AS Row, *
FROM Locations
WHERE UserId = 12345) AS SubQuery
WHERE Row > 1 -- or 2, or 5, or 34
การค้นหาคำค้นหาย่อยแบบง่ายที่เรียงลำดับจากมากไปหาน้อยตามด้วยการเรียงลำดับจากคอลัมน์เดียวกันจากน้อยไปหามากจะเป็นเคล็ดลับ
SELECT * FROM
(SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
ORDER BY t1.[column]
SELECT TOP 10*from TABLE1 ORDER BY ID DESC
โดยที่ ID คือคีย์หลักของ TABLE1
ขั้นแรกให้สร้างดัชนีในแบบสอบถามย่อยตามลำดับเดิมของตารางโดยใช้:
ROW_NUMBER () OVER (ORDER BY (SELECT NULL) ) AS RowIndex
จากนั้นเรียงลำดับตารางจากRowIndex
คอลัมน์ที่คุณสร้างในแบบสอบถามหลัก:
ORDER BY RowIndex DESC
และสุดท้ายใช้TOP
กับจำนวนแถวที่คุณต้องการ:
SELECT TOP 1 * --(or 2, or 5, or 34)
FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL) ) AS RowIndex, *
FROM MyTable) AS SubQuery
ORDER BY RowIndex DESC