sql >> Base de Datos >  >> RDS >> PostgreSQL

Cuente la aparición de valores en un atributo serializado (matriz) en el panel de Active Admin (Rails, Active admin 1.0, base de datos Postgresql, postgres_ext gem)

No puedo pensar en ninguna forma limpia de obtener los resultados que busca a través de ActiveRecord, pero es bastante fácil en SQL.

Todo lo que realmente estás tratando de hacer es abrir el deal_goal arreglos y construir un histograma basado en los arreglos abiertos. Puede expresar eso directamente en SQL de esta manera:

with expanded_deals(id, goal) as (
    select id, unnest(deal_goal)
    from deals
)
select goal, count(*) n
from expanded_deals
group by goal

Y si desea incluir los cuatro objetivos incluso si no aparecen en ninguno de los deal_goal s luego simplemente lance un LEFT JOIN para decirlo:

with
    all_goals(goal) as (
        values ('traffic'),
               ('acquisition'),
               ('branding'),
               ('qualification')
    ),
    expanded_deals(id, goal) as (
        select id, unnest(deal_goal)
        from deals
    )
select all_goals.goal goal,
       count(expanded_deals.id) n
from all_goals
left join expanded_deals using (goal)
group by all_goals.goal

Demostración de SQL :http://sqlfiddle.com/#!15/3f0af/20

Lance uno de esos en un select_rows llama y te daremos tus datos:

Deal.connection.select_rows(%q{ SQL goes here }).each do |row|
  goal = row.first
  n    = row.last.to_i
  #....
end

Probablemente están sucediendo muchas cosas aquí con las que no está familiarizado, así que le explicaré un poco.

En primer lugar, estoy usando WITH y Common Table Expressions (CTE) para simplificar las SELECCIONES. WITH es una característica estándar de SQL que le permite producir macros SQL o tablas temporales en línea de algún tipo. En su mayor parte, puede tomar el CTE y colocarlo directamente en la consulta donde se encuentra su nombre:

with some_cte(colname1, colname2, ...) as ( some_pile_of_complexity )
select * from some_cte

es así:

select * from ( some_pile_of_complexity ) as some_cte(colname1, colname2, ...)

Los CTE son la forma SQL de refactorizar una consulta/método demasiado complejo en piezas más pequeñas y fáciles de entender.

unnest es una función de matriz que desempaqueta una matriz en filas individuales. Así que si dices unnest(ARRAY[1,2]) , recuperas dos filas:1 y 2 .

VALORES en PostgreSQL se usa para, más o menos, generar tablas constantes en línea. Puede usar VALORES en cualquier lugar donde pueda usar una tabla normal, no es solo una sintaxis que agrega un INSERTAR para decirle a la base de datos qué valores insertar. Eso significa que puedes decir cosas como esta:

select * from (values (1), (2)) as dt

y obtener las filas 1 y 2 afuera. Lanzar esos VALORES en un CTE hace que las cosas sean agradables y legibles y hace que se vea como cualquier tabla antigua en la consulta final.