Bagaimana SQL Delete menggunakan sub kueri

15

Kode berikut ditambahkan oleh salah satu pengembang kami untuk menghapus rekaman duplikat dari tabel:

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

Ketika meninjau kode, saya berasumsi bahwa itu tidak akan berfungsi, namun mengujinya di lingkungan pengujian kami (SQL 2014) menunjukkan bahwa itu berhasil!

Bagaimana SQL tahu untuk menyelesaikan sub kueri dan menghapus catatan table?

Greg
sumber

Jawaban:

14

Yang subqueryAnda miliki dalam kode Anda disebut tabel turunan . Ini bukan tabel dasar tetapi tabel yang "hidup" selama waktu kueri berjalan. Seperti tampilan (yang juga disebut tabel yang dilihat ) - dan dalam versi terbaru, CTE merupakan cara lain ke-4 untuk "mendefinisikan" tabel di dalam kueri - mereka mirip dengan tabel dalam banyak cara. Anda dapat selectdari mereka, Anda dapat menggunakannya di fromatau ke joinmereka ke tabel lain (basis atau tidak!).

Dalam beberapa DBMS, (tidak semua DBMS menerapkan ini dengan cara yang sama) tabel / tampilan ini dapat diupdate . Dan "dapat diperbarui" berarti bahwa kita juga dapat update, insertke atau deletedari mereka.

Namun ada batasan dan ini diharapkan. Bayangkan jika subqueryitu adalah gabungan 2 (atau 17 tabel). Apa deleteartinya itu? (dari tabel mana baris harus dihapus?) Tampilan yang dapat diperbarui adalah masalah yang sangat rumit . Ada sebuah buku (2012) baru-baru ini, seluruhnya tentang hal ini, ditulis oleh Chris Date, ahli terkenal dalam teori relasional: View Memperbarui dan Teori Relasional .

Ketika tabel turunan (atau tampilan) adalah kueri yang sangat sederhana, seperti itu hanya memiliki satu tabel dasar (mungkin dibatasi oleh a WHERE) dan tidak GROUP BY, maka setiap baris dari tabel turunan berhubungan dengan satu baris di tabel dasar yang mendasarinya, jadi itu adalah * mudah diperbarui, disisipkan, atau dihapus dari ini.

Ketika kode di dalam subquery lebih kompleks, itu tergantung pada apakah baris dari tabel / tampilan yang diturunkan dapat dilacak / diselesaikan ke baris dari salah satu tabel dasar yang mendasarinya.

Untuk SQL Server, Anda dapat membaca lebih banyak di Updatable Views paragraf dalam MSDN: CREATE VIEW.

Tampilan yang Dapat Diperbarui

Anda bisa memodifikasi data tabel dasar yang mendasari melalui tampilan, selama kondisi berikut ini benar:

  • Setiap modifikasi, termasuk UPDATE,, INSERTdan DELETEpernyataan, harus merujuk kolom hanya dari satu tabel dasar.

  • Kolom yang sedang diubah dalam tampilan harus secara langsung merujuk data yang mendasarinya di kolom tabel. Kolom tidak dapat diturunkan dengan cara lain, seperti melalui yang berikut:

  • Fungsi agregat: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, dan VARP.

  • Suatu perhitungan. Kolom tidak dapat dihitung dari ekspresi yang menggunakan kolom lain. Kolom yang dibentuk dengan menggunakan operator set UNION, UNION ALL, CROSSJOIN, EXCEPT, dan INTERSECT jumlah yang perhitungan dan juga tidak diupdate.

  • Kolom yang dimodifikasi tidak terpengaruh oleh GROUP BY, HAVINGatau DISTINCTklausa.

  • TOPtidak digunakan di mana pun di select_statement tampilan bersama dengan WITH CHECK OPTIONklausa.

Pembatasan sebelumnya berlaku untuk subkueri apa pun dalam FROMklausa tampilan, sama seperti mereka berlaku untuk tampilan itu sendiri. Secara umum, Mesin Basis Data harus dapat melacak modifikasi dari definisi tampilan menjadi satu tabel dasar.


Sebenarnya deletelebih mudah, tidak serumit itu update. SQL Server hanya perlu kunci primer atau cara lain untuk mengidentifikasi baris dari tabel dasar mana yang harus dihapus. Sebab update, ada batasan (agak jelas) tambahan yang tidak dapat kami perbarui kolom yang dihitung. Anda dapat mencoba mengubah kueri Anda untuk melakukan pembaruan. Memperbarui CreatedDateTimemungkin akan berfungsi dengan baik tetapi mencoba memperbarui RowNumberkolom yang dihitung akan memunculkan kesalahan. Dan insertbahkan lebih kompleks, karena kita harus memberikan nilai untuk semua kolom tabel dasar yang tidak memiliki DEFAULTkendala.

ypercubeᵀᴹ
sumber
4

Sangat mudah untuk melihat ketika Anda melihat rencana kueri. Dalam kasus Anda, paket hanya berisi operator Segment and Sequence Project tambahan untuk menangani nomor baris. Jenis operasi ini hanya berfungsi ketika SQL Server benar-benar dapat menyelesaikan tabel yang mendasarinya.

Menghapus dari subkueri dan CTE didukung penuh dan sangat efisien, terutama untuk menghapus duplikat. Saya juga sepertinya ingat menggunakannya pada versi SQL Server yang lebih lama.

Lebih banyak di posting blog lama saya.

Daniel Hutmacher
sumber