Saya memiliki database Postgresql di mana saya ingin melakukan beberapa penghapusan cascading. Namun, tabel tidak diatur dengan aturan ON DELETE CASCADE. Apakah ada cara saya bisa melakukan delete dan memberi tahu Postgresql untuk melakukan cascade sekali ini saja? Sesuatu yang setara dengan
DELETE FROM some_table CASCADE;
Jawaban untuk pertanyaan yang lebih lama ini membuatnya sepertinya tidak ada solusi seperti itu, tetapi saya pikir saya akan menanyakan pertanyaan ini secara eksplisit hanya untuk memastikan.
postgresql
Eli Courtwright
sumber
sumber
Jawaban:
Tidak. Untuk melakukannya hanya sekali, Anda cukup menulis pernyataan hapus untuk tabel yang ingin Anda juntai.
sumber
Jika Anda benar-benar menginginkan
DELETE FROM some_table CASCADE;
yang berarti " hapus semua baris dari tabelsome_table
", Anda dapat menggunakannyaTRUNCATE
sebagai gantiDELETE
danCASCADE
selalu didukung. Namun, jika Anda ingin menggunakan penghapusan selektif denganwhere
klausa,TRUNCATE
tidak cukup baik.GUNAKAN DENGAN PERAWATAN - Ini akan menjatuhkan semua baris dari semua tabel yang memiliki batasan kunci asing
some_table
dan semua tabel yang memiliki kendala pada tabel tersebut, dll.Postgres mendukung
CASCADE
dengan perintah TRUNCATE :Mudahnya ini bersifat transaksional (yaitu dapat diputar kembali), meskipun tidak sepenuhnya terisolasi dari transaksi bersamaan lainnya, dan memiliki beberapa peringatan lainnya. Baca dokumen untuk detailnya.
sumber
Saya menulis fungsi (rekursif) untuk menghapus baris apa pun berdasarkan kunci utamanya. Saya menulis ini karena saya tidak ingin membuat batasan saya sebagai "pada penghapusan kaskade". Saya ingin dapat menghapus set data yang kompleks (sebagai DBA) tetapi tidak mengizinkan programmer saya untuk dapat menghapus kaskade tanpa memikirkan semua akibatnya. Saya masih menguji fungsi ini, jadi mungkin ada bug di dalamnya - tapi tolong jangan coba-coba jika DB Anda memiliki kunci utama multi-kolom (dan dengan demikian asing). Selain itu, semua kunci harus dapat direpresentasikan dalam bentuk string, tetapi dapat ditulis dengan cara yang tidak memiliki batasan itu. Saya menggunakan fungsi ini SANGAT SPARINGLY, saya terlalu menghargai data saya untuk mengaktifkan kendala cascading pada semuanya. Pada dasarnya fungsi ini diteruskan dalam skema, nama tabel, dan nilai primer (dalam bentuk string), dan itu akan mulai dengan menemukan kunci asing di tabel itu dan memastikan data tidak ada - jika ada, itu secara rekursif menyebut dirinya sendiri pada data yang ditemukan. Ini menggunakan array data yang sudah ditandai untuk dihapus untuk mencegah loop tak terbatas. Silakan mengujinya dan beri tahu saya cara kerjanya untuk Anda. Catatan: Agak lambat. Saya menyebutnya seperti ini:
select delete_cascade('public','my_table','1');
sumber
IN
operator dengan sub-pilih bukan=
(jadi langkah menggunakan set logika) itu akan menjadi jauh lebih cepat.Jika saya mengerti dengan benar, Anda harus dapat melakukan apa yang Anda inginkan dengan menjatuhkan batasan kunci asing, menambahkan yang baru (yang akan mengalir), melakukan hal-hal Anda, dan menciptakan kembali batasan kunci asing yang membatasi.
Sebagai contoh:
Tentu saja, Anda harus mengabstraksikan hal-hal seperti itu menjadi sebuah prosedur, demi kesehatan mental Anda.
sumber
Saya tidak bisa mengomentari jawaban Palehorse jadi saya menambahkan jawaban saya sendiri. Logika Palehorse baik-baik saja tetapi efisiensi bisa buruk dengan set data besar.
Lebih cepat jika Anda memiliki indeks pada kolom dan kumpulan data lebih besar dari beberapa catatan.
sumber
Ya, seperti yang orang lain katakan, tidak ada nyaman 'HAPUS DARI my_table ... CASCADE' (atau setara). Untuk menghapus catatan anak asing yang dilindungi kunci tidak bertingkat dan leluhur yang dirujuk, opsi Anda meliputi:
Ini dengan sengaja bahwa menghindari batasan kunci asing tidak dibuat nyaman, saya berasumsi; tapi saya mengerti mengapa dalam keadaan tertentu Anda ingin melakukannya. Jika itu adalah sesuatu yang akan Anda lakukan dengan frekuensi tertentu, dan jika Anda ingin mengabaikan kebijaksanaan DBA di mana-mana, Anda mungkin ingin mengotomatiskannya dengan prosedur.
Saya datang ke sini beberapa bulan yang lalu mencari jawaban untuk pertanyaan "CASCADE DELETE just once" (awalnya ditanyakan lebih dari satu dekade yang lalu!). Saya mendapatkan jarak tempuh dari solusi cerdas Joe Love (dan varian Thomas CG de Vilhena), tetapi pada akhirnya use case saya memiliki persyaratan tertentu (penanganan referensi melingkar intra-tabel, untuk satu) yang memaksa saya untuk mengambil pendekatan yang berbeda. Pendekatan itu akhirnya menjadi recursively_delete (PG 10.10).
Saya telah menggunakan recursively_delete dalam produksi untuk sementara waktu, sekarang, dan akhirnya merasa (waspada) cukup percaya diri untuk membuatnya tersedia untuk orang lain yang mungkin berakhir di sini mencari ide. Seperti halnya solusi Joe Love, ini memungkinkan Anda untuk menghapus seluruh grafik data seolah-olah semua batasan kunci asing dalam database Anda sesaat disetel ke CASCADE, tetapi menawarkan beberapa fitur tambahan:
sumber
Anda dapat menggunakan untuk mengotomatisasi ini, Anda dapat menentukan batasan kunci asing
ON DELETE CASCADE
.Saya mengutip manual batasan kunci asing :
sumber
Saya mengambil jawaban Joe Love dan menulis ulang menggunakan
IN
operator dengan sub-pilihan alih-alih=
membuat fungsi lebih cepat (menurut saran Hubbitus):sumber
in
operator dan sub-kueri.Hapus dengan opsi kaskade hanya diterapkan pada tabel dengan kunci asing yang ditentukan. Jika Anda melakukan penghapusan, dan itu mengatakan Anda tidak bisa karena itu akan melanggar batasan kunci asing, kaskade akan menyebabkannya menghapus baris yang menyinggung.
Jika Anda ingin menghapus baris terkait dengan cara ini, Anda harus menentukan kunci asing terlebih dahulu. Juga, ingat bahwa kecuali Anda secara eksplisit memerintahkannya untuk memulai transaksi, atau Anda mengubah default, itu akan melakukan komit otomatis, yang mungkin sangat memakan waktu untuk dibersihkan.
sumber