จะลบแถวบนสุด 1,000 แถวจากตารางโดยใช้ Sql Server 2008 ได้อย่างไร


108

ฉันมีตารางใน SQL Server ฉันต้องการลบ 1,000 แถวแรกออกจากมัน อย่างไรก็ตามฉันลองแล้ว แต่แทนที่จะลบแถวบนสุด 1,000 แถวมันจะลบแถวทั้งหมดในตาราง

นี่คือรหัส:

delete from [mytab] 
select top 1000 
a1,a2,a3
from [mytab]

8
คุณต้อง ORDER BY เพื่อให้มีความหมาย TOP: ดูคำตอบ @ Martin สมิ ธ ซึ่งเป็นเพียงหนึ่งในห้าจะมีนี้ บางครั้งฉันก็สิ้นหวัง
gbn

2
คุณต้องการที่จะลบใด ๆ 1,000 แถว? แค่สุ่มเลือก? หรือตัวอย่างเช่นแถวที่เก่าที่สุด 1,000 อันดับแรก
นิค Chammas

13
คุณลบตารางทั้งหมดเนื่องจากdelete from [mytab]เป็นคำสั่งเดียวและselect top ...เป็นอีกคำสั่งหนึ่ง
Nick Chammas

2
คุณไม่จำเป็นต้องสั่งซื้อด้านบนขึ้นอยู่กับว่าทำไมคุณถึงทำ TOP หากคุณต้องการลบ 10 ล้านแถวและมีพื้นที่บันทึก 1 GB ให้ใช้ Delete TOP (10000) จาก dbo.myTable (ด้วยประโยคที่คุณเลือก) และเรียกใช้ต่อไปจนกว่าจะไม่มีแถวให้ลบอีก ใครจะสนใจถ้าตามอำเภอใจ การเรียงลำดับทำให้การสืบค้นช้าลงเท่านั้น
tvanharp

1
ฉันตระหนักดีว่านี่เป็นคำถามที่โบราณ (ในปีที่ผ่านมา) แต่ฉันไม่คิดว่ามันเป็นสิ่งสำคัญที่คนพิจารณาความเห็นของ @gbn ในขณะที่ความคิดเห็นของเขาใช้ไม่ได้กับสถานการณ์ของฉัน (พยายามลบบล็อกของบันทึกโดยไม่ทำให้เกิดปัญหา LOCK แต่ไม่สนใจลำดับที่จะลบ) อาจนำไปใช้กับสถานการณ์ของคุณได้มาก ตรวจสอบให้แน่ใจว่าคุณได้พิจารณาก่อนที่จะใช้คำตอบด้านล่างแบบสุ่มสี่สุ่มห้าซึ่งไม่มีคำสั่ง ORDER BY
Andrew Steitz

คำตอบ:


196

รหัสที่คุณพยายามเป็นจริงสองคำสั่ง ตามมาด้วยDELETESELECT

คุณไม่ได้กำหนดTOPว่าเรียงตามอะไร

สำหรับเกณฑ์การสั่งซื้อเฉพาะการลบออกจากCTEหรือนิพจน์ตารางที่คล้ายกันเป็นวิธีที่มีประสิทธิภาพมากที่สุด

;WITH CTE AS
(
SELECT TOP 1000 *
FROM [mytab]
ORDER BY a1
)
DELETE FROM CTE

13
สำหรับผู้ที่สงสัยว่าทำไมคุณถึงทำไม่ได้DELETE TOP (1000) FROM table ORDER BY columnโปรดอ่านสิ่งนี้ : "แถวที่อ้างอิงในนิพจน์ TOP ที่ใช้กับ INSERT, UPDATE, MERGE หรือ DELETE จะไม่เรียงตามลำดับใด ๆ "
Nick Chammas

3
@ แม็กนัสใช่ ไม่ใช่ปี 2000 อาจเป็นไปได้ที่จะใช้ตารางที่ได้รับในปี 2000 ฉันไม่มีอินสแตนซ์ที่จะทดสอบด้วย
Martin Smith


2
ฉันทำวิธีที่แตกต่างออกไปเล็กน้อย (แม้ว่าฉันคิดว่า CTE อาจจะดูดีกว่านี้): ลบ T1 จาก (เลือกอันดับสูงสุด 1,000 * จาก [MYTAB] ORDER BY A1) T1;
Abacus

4
@Liam - เพียงเพราะถ้ามีคำสั่งใด ๆ ก่อนหน้า CTE สิ่งนี้จะต้องถูกปิดท้ายด้วยอัฒภาคดังนั้นการต่อท้ายจะเป็นการWITHร้องเรียนจากผู้ที่ยังไม่ได้ทำเช่นนั้น
Martin Smith

86

อาจจะดีกว่าสำหรับ sql2005 + ที่จะใช้:

DELETE TOP (1000)
FROM [MyTab]
WHERE YourConditions

สำหรับ Sql2000:

DELETE FROM [MyTab]
WHERE YourIdField IN 
(
  SELECT TOP 1000 
    YourIdField 
  FROM [MyTab]
  WHERE YourConditions
)

แต่

หากคุณต้องการลบชุดย่อยเฉพาะของแถวแทนที่จะเป็นชุดย่อยที่กำหนดเองคุณควรระบุลำดับของการสืบค้นย่อยอย่างชัดเจน:

DELETE FROM [MyTab]
WHERE YourIdField IN 
(
  SELECT TOP 1000 
    YourIdField 
  FROM [MyTab]
  WHERE YourConditions
  ORDER BY ExplicitSortOrder
)

ขอบคุณ tp @gbn ที่กล่าวถึงและเรียกร้องคำตอบที่ชัดเจนและแน่นอนยิ่งขึ้น


3
@gbn อาจจะไม่มีประโยชน์สำหรับคุณ แต่ก็ยังคงเป็นสิ่งที่คำถามกำลังถามอยู่
Joachim Isaksson

1
@ Joachim Isaksson: ไปอ่านเกี่ยวกับ TOP แล้วกลับมา ไม่มีสิ่งที่เรียกว่า TOP ที่ไม่มี ORDER BY ในชุด หรือไปหาข้อมูลอ้างอิงที่พิสูจน์ได้ว่าฉันคิดผิด ... เพื่อช่วยคุณในการค้นหาsqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/20/…และblogs.technet.com/b/wardpond/archive /
2550/07/19

1
@gbn ไม่มีเงื่อนไขใด ๆ เกี่ยวกับแถวที่จะลบดังนั้น ORDER BY ในแบบสอบถามย่อยจึงไร้ประโยชน์
Oleg Dok

1
@gbn คุณพูดถึง WHERE ในแบบสอบถามย่อยหรือไม่ - ฉันกรอง 1,000 แถวโดยพลการภายในเกณฑ์ที่เลือกแล้วลบออก สถานการณ์ที่ถูกต้อง? ใช่. ถ้าฉันเพิ่ม ORDER BY NEWID () หรืออะไรก็ตามที่ไม่มีการเปลี่ยนแปลง - ฉันยังคงลบ 1,000 แถวที่กรองตามเกณฑ์ที่เลือก
Oleg Dok

8
@gbn ในกรณีที่คุณกำลังมองหาการใช้ TOP ที่ถูกต้องโดยไม่ต้อง ORDER BY: สิ่งที่ทำให้ฉันมาที่นี่คือฉันต้องลบแถวทั้งหมดที่ตรงกับเกณฑ์บางอย่าง แต่ด้วยเหตุผลด้านประสิทธิภาพฉันไม่ต้องการให้มันลบมากกว่า 10,000 แถว ขณะนั้น. ฉันไม่สนใจว่าจะลบแถวไหนเพราะฉันจะเรียกใช้คำสั่งอีกครั้งในบางช่วงจนกว่าแถวนั้นจะหายไปทั้งหมด
Richiban


6
delete from [mytab]
where [mytab].primarykeyid in
(
select top 1000 primarykeyid
from [mytab]
)

4
ไร้ประโยชน์: TOP ที่ไม่มี ORDER BY ให้แถวตามอำเภอใจ
gbn

4
@gbn อาจจะไม่มีประโยชน์สำหรับคุณ แต่ก็ยังคงเป็นสิ่งที่คำถามกำลังถามอยู่
Joachim Isaksson

3
@gbn ฉันไม่ได้อ้างว่ามีลำดับการจัดเรียงเริ่มต้นหรือว่าแบบสอบถามนั้นมีประโยชน์ในทางใดทางหนึ่งฉันเพิ่งเตือนคุณว่าคำถามไม่ได้ถามคำถามดังนั้นคุณจะแนะนำให้สั่งซื้ออะไร
Joachim Isaksson

2
@gbn ฉันไม่รู้ว่าทำไมคุณถึงเป็นศัตรูกับทุกคนมากกว่าสิ่งที่เป็นจุดเริ่มต้น ฉันไม่ได้อ้างว่าคำตอบของฉันคือจุดจบทั้งหมดมันเป็นเพียงคำแนะนำเพื่อช่วยเหลือใครบางคน ฉันคิดว่าความสำคัญคือกุญแจที่กลับมาจากแบบสอบถามย่อยที่นี่
Jason Dam

2
นี่อาจเป็นทั้งหมดที่ผู้ถามกำลังมองหา ฉันแค่จะเพิ่มบันทึกเพื่อให้คนอื่นอ่านเพื่อเน้นว่าแถวที่ลบโดยคำสั่งดังกล่าวไม่รับประกันว่าจะอยู่ในลำดับใด ๆ
Nick Chammas

3
SET ROWCOUNT 1000;

DELETE FROM [MyTable] WHERE .....

2
เมื่อจัดการกับเพียง 1,000 แถวมันสำคัญจริงหรือ ?? หากเป็น 100,000,000 แถวคะแนนของคุณอาจถูกต้อง แต่มีเพียง 1,000 แถวนี่เป็นวิธีที่ง่ายที่สุดที่เสนอสำหรับ SQL 2008
Joe Bourne

1

เป็นไปอย่างรวดเร็ว ลองมัน:

DELETE FROM YourTABLE
FROM (SELECT TOP XX PK FROM YourTABLE) tbl
WHERE YourTABLE.PK = tbl.PK

แทนที่YourTABLEด้วยชื่อตาราง XXด้วยตัวเลขเช่น 1000 pkคือชื่อของเขตข้อมูลคีย์หลักของตารางของคุณ


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