SQL Delete สามารถใช้คำสั่งย่อยได้อย่างไร


15

รหัสต่อไปนี้ถูกเพิ่มโดยหนึ่งในนักพัฒนาของเราเพื่อลบระเบียนที่ซ้ำกันออกจากตาราง:

DELETE  SubQuery

FROM
(
    SELECT  ID
            ,FK1
            ,FK2
            ,CreatedDateTime
            ,ROW_NUMBER() OVER(PARTITION BY FK1, FK2 ORDER BY CreatedDateTime) AS RowNumber

    FROM    Table
)
AS SubQuery

WHERE   RowNumber > 1

เมื่อตรวจสอบรหัสฉันคิดว่ามันจะไม่ทำงานอย่างไรก็ตามการทดสอบในสภาพแวดล้อมการทดสอบของเรา (SQL 2014) แสดงให้เห็นว่ามันเป็นเช่นนั้น!

SQL ทราบได้อย่างไรว่าสามารถแก้ไขคิวรีย่อยและลบระเบียนได้tableอย่างไร

คำตอบ:


14

subqueryคุณมีในรหัสของคุณเรียกว่าตารางมา มันไม่ใช่ตารางฐาน แต่เป็นตารางที่ "อยู่" ในช่วงเวลาที่แบบสอบถามทำงาน เช่นเดียวกับมุมมอง (ซึ่งเรียกอีกอย่างว่าตารางที่ดู ) - และในCTEรุ่นล่าสุดซึ่งเป็นอีกวิธีที่ 4 ในการ "กำหนด" ตารางภายในแบบสอบถาม - มันคล้ายกับตารางในหลาย ๆ วิธี คุณสามารถselectจากพวกเขาคุณสามารถใช้พวกเขาในfromหรือเพื่อjoinพวกเขาไปยังตารางอื่น ๆ (ฐานหรือไม่!)

ใน DBMS บางตัว (ไม่ใช่ DBMS ทั้งหมดที่ใช้วิธีนี้เหมือนกัน) ตาราง / มุมมองเหล่านี้สามารถอัปเดตได้ และ "ปรับปรุงได้" หมายความว่าเราสามารถยังupdate, insertเข้าหรือdeleteจากพวกเขา

มีข้อ จำกัด อยู่และคาดว่าจะเป็นเช่นนี้ ลองคิดดูว่าการsubqueryเข้าร่วมเป็น 2 (หรือ 17 ตาราง) ถ้าเช่นdeleteนั้นจะหมายความว่าอย่างไร (จากตารางที่ควรแถวถูกลบ?) มองเห็นวิวปรับปรุงได้เป็นเรื่องที่มีความซับซ้อนมาก มีที่ผ่านมา (2012) หนังสือทั้งหมดในเรื่องนี้ที่เขียนโดยคริสวันที่ผู้เชี่ยวชาญที่รู้จักกันดีในทฤษฎีความสัมพันธ์เป็น: ดูการอัปเดตและทฤษฎีสัมพันธ์

เมื่อตารางที่ได้รับ (หรือมุมมอง) เป็นแบบสอบถามที่ง่ายมากเช่นมีเพียงตารางฐานเดียว (อาจถูก จำกัด โดย a WHERE) และไม่ใช่GROUP BYจากนั้นทุกแถวของตารางที่ได้รับจะสอดคล้องกับหนึ่งแถวในตารางฐานที่อยู่ข้างใต้ดังนั้นจึงเป็น ง่าย*เพื่ออัปเดตแทรกหรือลบจากสิ่งนี้

เมื่อรหัสภายในแบบสอบถามย่อยมีความซับซ้อนมากกว่านั้นขึ้นอยู่กับว่าแถวของตาราง / มุมมองที่ได้รับนั้นสามารถสืบหา / แก้ไขไปยังแถวจากหนึ่งในตารางฐานพื้นฐานได้หรือไม่

สำหรับ SQL Server คุณสามารถอ่านเพิ่มเติมในวรรคชมปรับปรุงได้ใน CREATE VIEWMSDN:

มุมมองที่อัปเดตได้

คุณสามารถปรับเปลี่ยนข้อมูลของตารางพื้นฐานผ่านมุมมองตราบใดที่เงื่อนไขต่อไปนี้เป็นจริง:

  • การปรับเปลี่ยนใด ๆ รวมทั้งUPDATE, INSERTและDELETEงบคอลัมน์อ้างอิงต้องเริ่มต้นเพียงตารางฐานหนึ่ง

  • คอลัมน์ที่กำลังแก้ไขในมุมมองจะต้องอ้างอิงข้อมูลพื้นฐานในคอลัมน์ตารางโดยตรง คอลัมน์ไม่สามารถรับได้ด้วยวิธีอื่นเช่นผ่านต่อไปนี้:

  • ฟังก์ชันการรวม: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VARและVARPและ

  • การคำนวณ คอลัมน์ไม่สามารถคำนวณได้จากนิพจน์ที่ใช้คอลัมน์อื่น คอลัมน์ที่จะเกิดขึ้นโดยใช้ประกอบชุดUNION, UNION ALL, CROSSJOIN, EXCEPTและINTERSECT จำนวนเงินเพื่อการคำนวณและจะยังไม่สามารถปรับปรุง

  • คอลัมน์การแก้ไขจะไม่ได้รับผลกระทบจากGROUP BY, HAVINGหรือDISTINCTคำสั่ง

  • TOPไม่ได้ใช้ที่ใดก็ได้ใน select_statement ของมุมมองพร้อมกับส่วนWITH CHECK OPTIONคำสั่ง

ข้อ จำกัด ก่อนหน้านี้นำไปใช้กับแบบสอบถามย่อยใด ๆ ในFROMส่วนของมุมมองเช่นเดียวกับที่ใช้กับมุมมองตัวเอง โดยทั่วไปแล้ว Database Engine จะต้องสามารถติดตามการแก้ไขจากนิยามการดูไปยังตารางฐานเดียวอย่างไม่น่าสงสัย


ที่จริงdeleteเป็นเรื่องง่าย, updateซับซ้อนน้อยกว่า SQL Server ต้องการคีย์หลักหรือวิธีอื่นเพื่อระบุแถวของตารางฐานที่จะถูกลบ สำหรับupdateมีข้อ จำกัด เพิ่มเติม (ค่อนข้างชัดเจน) ว่าเราไม่สามารถอัปเดตคอลัมน์ที่คำนวณได้ คุณสามารถลองปรับเปลี่ยนแบบสอบถามเพื่อทำการอัพเดท การอัปเดตCreatedDateTimeอาจจะใช้ได้ แต่การพยายามอัปเดตRowNumberคอลัมน์ที่คำนวณแล้วจะทำให้เกิดข้อผิดพลาด และinsertมีความซับซ้อนมากขึ้นเนื่องจากเราต้องระบุค่าสำหรับคอลัมน์ทั้งหมดของตารางฐานที่ไม่มีDEFAULTข้อ จำกัด


4

เป็นเรื่องง่ายที่จะเห็นเมื่อคุณดูแผนแบบสอบถาม ในกรณีของคุณแผนจะมีตัวดำเนินการโครงการเซกเมนต์และลำดับเพิ่มเติมเพื่อจัดการหมายเลขแถว การทำงานประเภทนี้ใช้ได้เฉพาะเมื่อ SQL Server สามารถแก้ไขตารางที่เกี่ยวข้องได้

การลบจากเคียวรีย่อยและ CTEs ได้รับการสนับสนุนอย่างสมบูรณ์และมีประสิทธิภาพมากโดยเฉพาะอย่างยิ่งสำหรับการลบสำเนาที่ซ้ำกัน ฉันดูเหมือนจะจำได้ว่าใช้มันกับ SQL Server รุ่นเก่ากว่า

เพิ่มเติมในโพสต์บล็อกเก่าของฉัน

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