Gunakan KASUS untuk memilih kolom dalam kueri UPDATE?

13

Saya dapat menggunakan CASEuntuk memilih kolom mana yang akan ditampilkan dalam SELECTkueri (Postgres), seperti:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

Apakah mungkin ada yang serupa ketika melakukan UPDATEkueri di Postgres (yaitu memilih kolom mana yang harus diperbarui)? Saya berasumsi tidak karena saya tidak dapat menemukan apa pun tentang ini, tetapi mungkin seseorang memiliki alternatif yang cerdas (selain menggunakan prosedur atau memperbarui setiap kolom menggunakan a CASEuntuk menentukan apakah nilai kolom harus diberi nilai baru atau hanya menetapkan kembali yang sudah ada nilai). Jika tidak ada alternatif yang mudah, tentu saja saya akan menerimanya sebagai jawaban juga.

Info tambahan : Dalam kasus saya, saya memiliki 14 kolom potensial yang dapat diperbarui, dengan hanya satu yang diperbarui per baris yang cocok (tabel yang akan diperbarui bergabung dengan yang lain dalam kueri). Jumlah baris yang akan diperbarui kemungkinan besar akan bervariasi, bisa puluhan atau ratusan. Saya percaya indeks sudah siap untuk kondisi bergabung.

newenglander
sumber

Jawaban:

26

Jika Anda menentukan kolom harus diperbarui maka itu akan selalu diperbarui, tetapi Anda dapat mengubah nilai yang Anda masukkan secara kondisional dan mengembalikan nilai aslinya tergantung pada kondisi Anda. Sesuatu seperti:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Jadi, jika kondisinya tidak tepat untuk pembaruan ke kolom tertentu, Anda cukup memberi umpan balik nilainya saat ini.

Perhatikan bahwa setiap baris yang cocok akan melihat pembaruan (bahkan jika semua kolom akhirnya disetel ke nilai yang sudah mereka miliki) kecuali jika Anda secara eksplisit mengunci keadaan ini saat Anda memfilter klausa ON dan WHERE, yang bisa menjadi masalah kinerja (akan ada menjadi tulisan, indeks akan diperbarui, pemicu yang tepat akan diaktifkan, ...) jika tidak dimitigasi.

David Spillett
sumber
Terima kasih atas tip tentang segala sesuatu yang diperbarui, jika ini lambat, saya dapat mengambil saran @Colin 't Hart untuk memiliki beberapa pernyataan pembaruan.
newenglander
Anda dapat mengurangi masalah itu dengan memastikan klausa ON dan WHERE Anda menyaring semua baris di mana tidak ada perubahan yang diperlukan, tetapi itu bisa berarti mengulang semua kondisi Anda baik dalam klausa SET dan klausa WHERE (kecuali ada pemeriksaan keseluruhan yang lebih sederhana yang 100% setara dengan semua kondisi yang digabungkan). Pada saat itu metode ini mungkin masih lebih efisien, tetapi metode banyak pembaruan mungkin lebih mudah dipertahankan.
David Spillett
Perlu diketahui juga bahwa memperbarui kolom dengan nilai yang sama akan menyebabkan pengulangan dibuat, lihat orainternals.wordpress.com/2010/11/04/…
Colin 't Hart
@Colin: Ya, setiap pembaruan akan melewati log transaksi DB termasuk pembaruan yang pada dasarnya NoOps karena memperbarui bidang untuk memiliki nilai yang sama seperti sebelumnya. Selain potensi masalah kinerja langsung, ini bisa menjadi faktor penting jika menggunakan replikasi, cadangan diferensial, pengiriman log, dan sebagainya, karena operasi pembaruan baris tambahan akan menambah ruang / bandwidth yang dibutuhkan untuk itu.
David Spillett
Terima kasih kepada Anda berdua untuk tipsnya, dalam kasus saya pernyataan pembaruan tunggal berfungsi dengan baik.
newenglander
5

Berapa banyak kombinasi kolom yang berbeda untuk diperbarui yang Anda miliki? Berapa banyak baris dari seluruh tabel akan diperbarui? Apakah ada indeks untuk akses cepat ke baris yang diperbarui?

Bergantung pada jawaban untuk pertanyaan-pertanyaan ini, Anda mungkin dapat menjalankan beberapa pernyataan pembaruan, satu untuk setiap kolom yang ingin Anda perbarui dan menempatkan kondisi pada nilai kolom itu di mana klausa pembaruan sehingga nol baris diperbarui jika kolom itu diperbarui memiliki nilai yang salah.

Coba dan pikirkan berbasis set, jangan menganggap bahwa pembaruan perlu memperbarui satu baris yang ditemukan oleh kunci utama.

Colin 't Hart
sumber
Terima kasih atas jawabannya. Saya telah menambahkan beberapa informasi lagi ke pertanyaan saya, saya harap itu bisa dimengerti. Itu alternatif yang baik dengan beberapa pernyataan pembaruan (saya lebih suka satu pernyataan pembaruan, tapi saya melihat ada keuntungan di sana).
newenglander
Ini mungkin jawaban yang saya cari tetapi maksud Anda meletakkan pembaruan column_x = new_value_for_x di mana @val = 0. Saya dapat mencoba sesuatu seperti itu. Terlihat lucu. Tidak lebih mudah dilakukan jika val = 0 mulai perbarui column_x = new_value_for_x dll.
CashCow
-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then '[email protected]'
       when FName = 'Riddick' then '[email protected]'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end
pengguna134695
sumber
Pembaruan ini hanya satu kolom, sementara penanya ingin tahu cara memperbarui kolom yang berbeda tergantung kondisi.
Colin 't Hart