Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Permintaan Ecto dan fungsi MySQL khusus dengan variabel arity

ORM luar biasa, sampai mereka bocor . Semua lakukan, akhirnya. Ecto masih muda (misalnya, hanya memperoleh kemampuan untuk OR di mana klausa bersama 30 hari yang lalu ), jadi belum cukup matang untuk mengembangkan API yang mempertimbangkan putaran SQL tingkat lanjut.

Mensurvei opsi yang memungkinkan, Anda tidak sendirian dalam permintaan tersebut. Ketidakmampuan untuk memahami daftar dalam fragmen (baik sebagai bagian dari order_by atau where atau di mana pun) telah disebutkan di Ecto issue #1485 , di StackOverflow , di Forum Ramuan Ramuan dan entri blog . Yang kemudian sangat instruktif. Lebih lanjut tentang itu sebentar lagi. Pertama, mari kita coba beberapa eksperimen.

Eksperimen #1: Seseorang mungkin pertama kali mencoba menggunakan Kernel.apply/3 untuk meneruskan daftar ke fragment , tapi itu tidak akan berhasil:

|> order_by(Kernel.apply(Ecto.Query.Builder, :fragment, ^ids))

Eksperimen #2: Maka mungkin kita bisa membangunnya dengan manipulasi string. Bagaimana kalau memberikan fragment string yang dibuat saat runtime dengan placeholder yang cukup untuk ditarik dari daftar:

|> order_by(fragment(Enum.join(["FIELD(id,", Enum.join(Enum.map(ids, fn _ -> "?" end), ","), ")"], ""), ^ids))

Manakah yang akan menghasilkan FIELD(id,?,?,?) diberikan ids = [1, 2, 3] . Tidak, ini juga tidak berhasil.

Eksperimen #3: Membuat keseluruhan, SQL final yang dibangun dari id, menempatkan nilai ID mentah langsung di string yang dibuat. Selain mengerikan, itu juga tidak berhasil:

|> order_by(fragment(Enum.join(["FIELD(id,", Enum.join(^ids, ","), ")"], "")))

Eksperimen #4: Ini membawa saya ke posting blog yang saya sebutkan. Di dalamnya, penulis meretas kekurangan or_where menggunakan sekumpulan makro yang telah ditentukan sebelumnya berdasarkan jumlah kondisi untuk digabungkan:

defp orderby_fragment(query, [v1]) do
  from u in query, order_by: fragment("FIELD(id,?)", ^v1)
end
defp orderby_fragment(query, [v1,v2]) do
  from u in query, order_by: fragment("FIELD(id,?,?)", ^v1, ^v2)
end
defp orderby_fragment(query, [v1,v2,v3]) do
  from u in query, order_by: fragment("FIELD(id,?,?,?)", ^v1, ^v2, ^v3)
end
defp orderby_fragment(query, [v1,v2,v3,v4]) do
  from u in query, order_by: fragment("FIELD(id,?,?,?)", ^v1, ^v2, ^v3, ^v4)
end

Meskipun ini berfungsi dan menggunakan ORM "dengan gandum" untuk berbicara, ini mengharuskan Anda memiliki jumlah bidang yang tersedia dan dapat dikelola. Ini mungkin atau mungkin bukan pengubah permainan.

Rekomendasi saya:jangan mencoba menyulap kebocoran ORM. Anda tahu pertanyaan terbaik. Jika ORM tidak menerimanya, tulis langsung dengan SQL mentah, dan dokumentasikan mengapa ORM tidak berfungsi. Lindungi di balik fungsi atau modul sehingga Anda dapat memiliki hak di masa mendatang untuk mengubah implementasinya. Suatu hari, ketika ORM menyusul, Anda dapat menulis ulang dengan baik tanpa efek pada sistem lainnya.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana menemukan perbedaan antara dua tanggal di MySQL

  2. Menggunakan skrip shell untuk memasukkan data ke database MYSQL jarak jauh

  3. Apa yang dikembalikan oleh MySQL DELETE yang berhasil? Bagaimana cara memeriksa apakah DELETE berhasil?

  4. Hasil loop berdasarkan kategori tetapi hanya menampilkan kategori sekali

  5. Cari di kolom Json dengan Laravel