Cara SQL-y
Pertama, mari kita selesaikan masalah di SQL, sehingga sintaks khusus Rails tidak menipu kita.
Pertanyaan SO ini adalah paralel yang cukup jelas:Menemukan duplikat nilai dalam Tabel SQL
Jawaban dari KM (kedua dari atas, tidak dicentang, saat ini) memenuhi kriteria Anda untuk mengembalikan semua rekaman duplikat beserta ID-nya. Saya telah memodifikasi KM SQL untuk mencocokkan Anda meja...
SELECT
m.id, m.title
FROM
movies m
INNER JOIN (
SELECT
title, COUNT(*) AS CountOf
FROM
movies
GROUP BY
title
HAVING COUNT(*)>1
) dupes
ON
m.title=dupes.title
Bagian di dalam INNER JOIN ( )
pada dasarnya adalah apa yang telah Anda hasilkan. Tabel yang dikelompokkan dari judul dan jumlah duplikat. Caranya adalah JOIN
memasukkannya ke movies
yang tidak dimodifikasi tabel, yang akan mengecualikan film apa pun yang tidak memiliki kecocokan dalam kueri penipuan.
Mengapa ini sangat sulit untuk dihasilkan di Rails? Bagian tersulitnya adalah, karena kita JOIN
ing movies
ke movies
, kita harus membuat alias tabel (m
dan dupes
dalam pertanyaan saya di atas).
Sayangnya, Rails tidak menyediakan cara bersih untuk mendeklarasikan alias ini. Beberapa referensi:
- Masalah Rails GitHub menyebutkan "bergabung" dan "alias". Kesengsaraan.
- Pertanyaan SO:Kueri ActiveRecord dengan tabel alias nama
Untungnya, karena kita sudah menguasai SQL, kita bisa menggunakan .find_by_sql
metode...
Movie.find_by_sql("SELECT m.id, m.title FROM movies m INNER JOIN (SELECT title, COUNT(*) FROM movies GROUP BY title HAVING COUNT(*)>1) dupes ON m.first=.first")
Karena kami memanggil Movie.find_by_sql
, ActiveRecord mengasumsikan SQL tulisan tangan kita dapat digabungkan ke dalam Movie
objek. Itu tidak memijat atau menghasilkan apa pun, yang memungkinkan kita melakukan alias kita.
Pendekatan ini memiliki kekurangan. Ini mengembalikan array dan bukan Relasi ActiveRecord, yang berarti tidak dapat dirantai dengan cakupan lain. Dan, dalam dokumentasi untuk find_by_sql
metode
, kami mendapat keputusasaan ekstra...
Jalan Rel
Sungguh, apa yang dilakukan SQL di atas? Itu mendapatkan daftar nama yang muncul lebih dari sekali. Kemudian, itu mencocokkan daftar itu dengan tabel asli. Jadi, mari kita lakukan itu menggunakan Rails.
titles_with_multiple = Movie.group(:title).having("count(title) > 1").count.keys
Movie.where(title: titles_with_multiple)
Kami memanggil .keys
karena kueri pertama mengembalikan hash. Kuncinya adalah gelar kami. where()
metode dapat mengambil sebuah array, dan kami telah memberikannya sebuah array dari judul. Pemenang.
Anda bisa berargumen bahwa satu baris Ruby lebih elegan daripada dua baris. Dan jika satu baris Ruby itu memiliki string SQL yang tertanam di dalamnya, seberapa elegan itu sebenarnya?
Semoga membantu!