ruby-on-rails - left - rails nested joins
ActiveRecord Count para contar filas devueltas por grupo en Rails (5)
La solución para mi situación parece ser reemplazar: group => ''tags.id'' con: select => ''DISTINCT tags.id'' en el hash de opciones antes de ejecutar el conteo.
count_options = options.clone
count_options.delete(:order)
if options[:group]
group_by = count_options[:group]
count_options.delete(:group)
count_options[:select] = "DISTINCT #{group_by}"
end
@item_count = @type.count(count_options)
Miré a mi alrededor y no pude encontrar ninguna respuesta a esto. Todas las respuestas involucraron recuentos que no usaron GROUP BY.
Fondo: Tengo un paginador que tomará las opciones para un ActiveRecord.find. Agrega una opción: límite y compensación y realiza la consulta. Lo que también debo hacer es contar el número total de registros (menos el límite), pero a veces la consulta contiene una opción: group y ActiveRecord.count intenta devolver todas las filas devueltas por GROUP BY junto con cada una de sus cuentas. Estoy haciendo esto en Rails 2.3.5.
Lo que quiero es que ActiveRecord.count devuelva el número de filas devueltas por GROUP BY.
Aquí hay un ejemplo de código que muestra una instancia de esto (usado para encontrar todas las etiquetas y ordenarlas por el número de publicaciones con esa etiqueta):
options = { :select => ''tags.*, COUNT(*) AS post_count'',
:joins => ''INNER JOIN posts_tags'', #Join table for ''posts'' and ''tags''
:group => ''tags.id'',
:order => ''post_count DESC'' }
@count = Tag.count(options)
options = options.merge { :offset => (page - 1) * per_page, :limit => per_page }
@items = Tag.find(options)
Con la opción: select, el Tag.count genera el siguiente SQL:
SELECT count(tags.*, COUNT(*) AS post_count) AS count_tags_all_count_all_as_post_count, tags.id AS tags_id FROM `tags` INNER JOIN posts_tags GROUP BY tags.id ORDER BY COUNT(*) DESC
Como puede ver, simplemente envolvió un COUNT () alrededor de ''tags. *, COUNT (*)'', y MySQL se queja sobre el COUNT dentro de un COUNT.
Sin la opción: select, genera este SQL:
SELECT count(*) AS count_all, tags.id AS tags_id FROM `tags` INNER JOIN posts_tags GROUP BY tags.id ORDER BY COUNT(*)
que devuelve todo el conjunto de resultados de GROUP BY y no el número de filas.
¿Hay alguna forma de evitar esto o tendré que hackear el paginador para tener en cuenta las consultas con GROUP BY (y cómo lo haría)?
Otra solución (hacky):
selection = Tag.where(...).group(...)
count = Tag.connection.select_value "select count(*) from (" + selection.to_sql + ") as x"
Parece que necesitarías manejar las consultas agrupadas por separado. Hacer una cuenta sin un grupo devuelve un entero, mientras que contar con un grupo devuelve un hash:
Tag.count
SQL (0.2ms) SELECT COUNT(*) FROM "tags"
=> 37
Tag.count(:group=>"tags.id")
SQL (0.2ms) SELECT COUNT(*) AS count_all, tags.id AS tags_id FROM "tags"
GROUP BY tags.id
=> {1=>37}
Si entiendo su pregunta correctamente, entonces debería funcionar si no usa Tag.count en absoluto. Especificar ''COUNT (*) AS post_count'' en su hash seleccionado debería ser suficiente. Por ejemplo:
@tag = Tag.first(options)
@tag.post_count
Como puede ver, el valor post_count de la consulta es accesible desde la instancia de @tag. Y si quieres obtener todas las etiquetas, entonces quizás algo como esto:
@tags = Tag.all(options)
@tags.each do |tag|
puts "Tag name: #{tag.name} posts: #{tag.post_count}"
end
Actualizar:
Count se puede llamar con qué atributo contar y también un parámetro: distintas
options = { :select => ''tags.*, COUNT(*) AS post_count'',
:joins => ''INNER JOIN posts_tags'', #Join table for ''posts'' and ''tags''
:group => ''tags.id'',
:order => ''post_count DESC'',
:offset => (page - 1) * per_page,
:limit => per_page }
@count = Tag.count(:id, :distinct => true, :joins => options[:joins])
@items = Tag.find(options)
Si está utilizando Rails 4 o 5, también puede hacer lo siguiente.
Tag.group(:id).count