Pertanyaan Bagaimana menjalankan sql perbaruan baku dengan pengikatan dinamis pada rel


Saya ingin mengeksekusi satu perbarui raw sql seperti di bawah ini:

update table set f1=? where f2=? and f3=?

SQL ini akan dieksekusi oleh ActiveRecord::Base.connection.execute, tetapi saya tidak tahu cara meneruskan nilai parameter dinamis ke dalam metode.

Bisakah seseorang memberi saya bantuan apa pun?


75
2017-12-19 13:04


asal


Jawaban:


Ini tidak terlihat seperti API Rails mengekspos metode untuk melakukan hal ini secara umum. Anda dapat mencoba mengakses koneksi yang mendasarinya dan menggunakan metode itu, mis. untuk MySQL:

st = ActiveRecord::Base.connection.raw_connection.prepare("update table set f1=? where f2=? and f3=?")
st.execute(f1, f2, f3)
st.close

Saya tidak yakin apakah ada konsekuensi lain untuk melakukan hal ini (koneksi dibiarkan terbuka, dll). Saya akan melacak kode Rails untuk pembaruan normal untuk melihat apa yang dilakukannya selain dari permintaan yang sebenarnya.

Menggunakan kueri yang disiapkan dapat menghemat sedikit waktu dalam database, tetapi kecuali Anda melakukan ini jutaan kali berturut-turut, Anda mungkin akan lebih baik hanya membangun pembaruan dengan substitusi Ruby yang normal, mis.

ActiveRecord::Base.connection.execute("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")

atau menggunakan ActiveRecord seperti yang dikatakan komentator.


79
2017-12-19 18:54



ActiveRecord::Base.connection mempunyai sebuah quote metode yang mengambil nilai string (dan secara opsional objek kolom). Jadi Anda bisa mengatakan ini:

ActiveRecord::Base.connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{ActiveRecord::Base.connection.quote(baz)}
EOQ

Catatan jika Anda berada dalam migrasi Rails atau objek ActiveRecord, Anda dapat mempersingkatnya menjadi:

connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{connection.quote(baz)}
EOQ

MEMPERBARUI: Seperti yang ditunjukkan @kolen, Anda harus menggunakannya exec_update sebagai gantinya. Ini akan menangani kutipan untuk Anda dan juga menghindari kebocoran memori. Tanda tangan bekerja agak berbeda meskipun:

connection.exec_update(<<-EOQ, "SQL", [[nil, baz]])
  UPDATE  foo
  SET     bar = $1
EOQ

Di sini parameter terakhir adalah larik tupel yang mewakili parameter pengikat. Di setiap tupel, entri pertama adalah tipe kolom dan yang kedua adalah nilainya. Kamu bisa memberi nil untuk tipe kolom dan Rails biasanya akan melakukan hal yang benar.

Ada juga exec_query, exec_insert, dan exec_delete, tergantung apa yang Anda butuhkan.


20
2017-07-01 23:01



Anda hanya harus menggunakan sesuatu seperti:

YourModel.update_all(
  ActiveRecord::Base.send(:sanitize_sql_for_assignment, {:value => "'wow'"})
)

Itu akan berhasil. Menggunakan ActiveRecord :: Base # send metode untuk memanggil sanitize_sql_for_assignment membuat Ruby (setidaknya versi 1.8.7) melewatkan fakta bahwa sanitize_sql_for_assignment sebenarnya adalah metode yang dilindungi.


4
2018-05-15 03:12



Terkadang akan lebih baik menggunakan nama kelas induk sebagai ganti nama tabel:

# Refers to the current class
self.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

Misalnya "Orang" kelas dasar, subclass (dan tabel database) "Klien" dan "Penjual" Alih-alih menggunakan:

Client.where(self.class.primary_key => id).update_all(created _at: timestamp)
Seller.where(self.class.primary_key => id).update_all(created _at: timestamp)

Anda dapat menggunakan objek dari kelas dasar dengan cara ini:

person.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

2
2017-11-29 20:58



Saya perlu menggunakan raw sql karena saya gagal mendapatkan composite_primary_keys berfungsi dengan activerecord 2.3.8. Jadi untuk mengakses tabel sqlserver 2000 dengan kunci primer gabungan, diperlukan sql mentah.

sql = "update [db].[dbo].[#{Contacts.table_name}] " +
      "set [COLUMN] = 0 " +
      "where [CLIENT_ID] = '#{contact.CLIENT_ID}' and CONTACT_ID = '#{contact.CONTACT_ID}'"
st = ActiveRecord::Base.connection.raw_connection.prepare(sql)
st.execute

Jika solusi yang lebih baik tersedia, silakan bagikan.


-8
2018-04-25 18:06



Di Rails 3.1, Anda harus menggunakan antarmuka kueri:

  • baru (atribut)
  • buat (atribut)
  • buat! (atribut)
  • temukan (id_or_array)
  • menghancurkan (id_or_array)
  • destroy_all
  • hapus (id_or_array)
  • Hapus semua
  • pembaruan (ids, update)
  • update_all (update)
  • ada?

perbarui dan update_all adalah operasi yang Anda butuhkan.

Lihat detailnya di sini: http://m.onkey.org/active-record-query-interface


-13
2017-11-11 09:40