Rails: chọn các giá trị duy nhất từ ​​một cột


238

Tôi đã có một giải pháp làm việc, nhưng tôi thực sự muốn biết tại sao điều này không hiệu quả:

ratings = Model.select(:rating).uniq
ratings.each { |r| puts r.rating }

Nó chọn, nhưng không in các giá trị duy nhất, nó in tất cả các giá trị, bao gồm cả các bản sao. Và nó có trong tài liệu: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields


2
Một ví dụ khác với uniq stackoverflow.com/questions/8369812/ từ
manish nautiyal

Câu trả lời:


449
Model.select(:rating)

Kết quả của việc này là một bộ sưu tập các Modelđối tượng. Không phải xếp hạng đơn giản. Và theo uniqquan điểm của họ, chúng hoàn toàn khác nhau. Bạn có thể sử dụng điều này:

Model.select(:rating).map(&:rating).uniq

hoặc cái này (hiệu quả nhất)

Model.uniq.pluck(:rating)

# rails 5+
Model.distinct.pluck(:rating)

Cập nhật

Rõ ràng, kể từ phiên bản 5.0.0.1, nó chỉ hoạt động trên các truy vấn "cấp cao nhất", như trên. Không hoạt động trên các proxy bộ sưu tập (ví dụ: "has_many").

Address.distinct.pluck(:city) # => ['Moscow']
user.addresses.distinct.pluck(:city) # => ['Moscow', 'Moscow', 'Moscow']

Trong trường hợp này, lặp lại sau khi truy vấn

user.addresses.pluck(:city).uniq # => ['Moscow']

Tôi đã làm một: nhóm (: xếp hạng) .collect {| r | r.rating} Vì map == sưu tầm, tôi có thể đọc về sintax này mà bạn đã sử dụng (&: rating) ở đâu? Tôi không thấy điều này trong tài liệu của Ruby.
alexandrecosta

@ user1261084: xem Biểu tượng # to_proc để hiểu .map (&: xếp hạng). PragDave giải thích
dbenhur

63
Điều đáng chú ý Model.uniq.pluck(:rating)là cách hiệu quả nhất để thực hiện việc này - điều này tạo ra SQL sử dụng SELECT DISTINCTthay vì áp dụng .uniqcho một mảng
Mikey

23
Trong Rails 5, Model.uniq.pluck(:rating)sẽ làModel.distinct.pluck(:rating)
thần kinh học

2
Nếu bạn muốn chọn các giá trị duy nhất từ ​​mối quan hệ has_many, bạn luôn có thể thực hiệnModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski

92

Nếu bạn sẽ sử dụng Model.select, thì bạn cũng có thể chỉ sử dụng DISTINCT, vì nó sẽ chỉ trả về các giá trị duy nhất. Điều này tốt hơn bởi vì nó có nghĩa là nó trả về ít hàng hơn và sẽ nhanh hơn một chút so với trả về một số hàng và sau đó báo cho Rails chọn các giá trị duy nhất.

Model.select('DISTINCT rating')

Tất nhiên, điều này được cung cấp cơ sở dữ liệu của bạn hiểu DISTINCTtừ khóa, và hầu hết nên.


6
Model.select("DISTINCT rating").map(&:rating)để có được một mảng chỉ xếp hạng.
Kris

Tuyệt vời cho những người có ứng dụng cũ sử dụng Rails 2.3
Mikey

3
Có..có hoạt động tuyệt vời - tuy nhiên, nhưng nó chỉ trả về thuộc tính DISTINCT. Làm thế nào bạn có thể trả về toàn bộ đối tượng Model miễn là khác biệt của nó? Vì vậy, bạn sẽ có quyền truy cập vào tất cả các thuộc tính trong mô hình trong trường hợp thuộc tính là duy nhất.
zero_cool

@Jackson_Sandland Nếu bạn muốn một đối tượng Model, điều đó cần phải được khởi tạo từ một bản ghi trong bảng. Nhưng bạn không chọn một bản ghi chỉ là một giá trị duy nhất (từ những gì có thể là nhiều bản ghi).
Benissimo

69

Điều này làm việc quá.

Model.pluck("DISTINCT rating")

Tôi tin rằng nhổ lông là Ruby 1.9.x trở lên. Bất cứ ai sử dụng phiên bản trước sẽ không có nó. Nếu bạn ở độ tuổi 1,9x trở lên, các tài liệu ruby ​​cho biết điều này cũng hoạt động: Model.uniq.pluck (: rating)
kakubei

6
plucklà một phương thức Rails> 3.2 thuần túy, không phụ thuộc vào Ruby 1.9.x Xem apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
Daniel Rikowski

34

Nếu bạn cũng muốn chọn thêm các trường:

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map { |m| [m.id, m.ratings] }

1
select extra fields<3 <3
cappie013

27
Model.uniq.pluck(:rating)

# SELECT DISTINCT "models"."rating" FROM "models"

Điều này có lợi thế của việc không sử dụng chuỗi sql và không khởi tạo mô hình


3
Điều này đưa ra một lỗi với Rails 5.1 / AR 5.1 => phương thức không xác định `uniq '
Graham Slick


5
Model.select(:rating).distinct

2
Đây là câu trả lời chính thức duy nhất cũng siêu hiệu quả. Mặc dù, thêm .pluck(:rating)vào cuối sẽ làm cho nó chính xác những gì OP yêu cầu.
Sheharyar

5

Nếu tôi đi đúng đường thì:

Truy vấn hiện tại

Model.select(:rating)

đang trả về mảng của đối tượng và bạn có truy vấn bằng văn bản

Model.select(:rating).uniq

uniq được áp dụng trên mảng đối tượng và mỗi đối tượng có id duy nhất. uniq đang thực hiện công việc của mình một cách chính xác vì mỗi đối tượng trong mảng là uniq.

Có nhiều cách để chọn xếp hạng khác biệt:

Model.select('distinct rating').map(&:rating)

hoặc là

Model.select('distinct rating').collect(&:rating)

hoặc là

Model.select(:rating).map(&:rating).uniq

hoặc là

Model.select(:name).collect(&:rating).uniq

Một điều nữa, truy vấn thứ nhất và thứ hai: tìm dữ liệu riêng biệt bằng truy vấn SQL.

Các truy vấn này sẽ được coi là "london" và "london" giống nhau có nghĩa là nó sẽ bỏ qua không gian, đó là lý do tại sao nó sẽ chọn "london" một lần trong kết quả truy vấn của bạn.

Truy vấn thứ ba và sau:

tìm dữ liệu bằng truy vấn SQL và cho dữ liệu riêng biệt được áp dụng ruby ​​uniq mehtod. các truy vấn này sẽ được coi là "london" và "london" khác nhau, đó là lý do tại sao nó sẽ chọn 'london' và 'london' cả trong kết quả truy vấn của bạn.

vui lòng thích hình ảnh đính kèm để hiểu rõ hơn và xem "Đã tham gia / đang chờ RFP".

nhập mô tả hình ảnh ở đây


6
map& collectlà bí danh cho cùng một phương thức, không cần cung cấp ví dụ cho cả hai.
Adam Lassek

4

Một số câu trả lời không tính đến OP muốn một loạt các giá trị

Các câu trả lời khác không hoạt động tốt nếu Mô hình của bạn có hàng nghìn hồ sơ

Điều đó nói rằng, tôi nghĩ rằng một câu trả lời tốt là:

    Model.uniq.select(:ratings).map(&:ratings)
    => "SELECT DISTINCT ratings FROM `models` " 

Bởi vì, trước tiên, bạn tạo một mảng Mô hình (với kích thước giảm dần do được chọn), sau đó bạn trích xuất thuộc tính duy nhất mà các mô hình đã chọn có (xếp hạng)


3

Nếu bất cứ ai đang tìm kiếm điều tương tự với Mongoid, đó là

Model.distinct(:rating)

cái này không hoạt động bây giờ, nó trả về bội số.
EUPHORAY

không trở lại khác biệt
dowi

2

Một cách khác để thu thập các cột uniq với sql:

Model.group(:rating).pluck(:rating)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.