PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Contar a ocorrência de valores em um atributo serializado (matriz) no painel Active Admin (Rails, Active admin 1.0, banco de dados Postgresql, gem postgres_ext)


Não consigo pensar em nenhuma maneira limpa de obter os resultados que você procura por meio do ActiveRecord, mas é muito fácil no SQL.

Tudo o que você está tentando fazer é abrir o deal_goal arrays e construir um histograma baseado nos arrays abertos. Você pode expressar isso diretamente no SQL desta maneira:
with expanded_deals(id, goal) as (
    select id, unnest(deal_goal)
    from deals
)
select goal, count(*) n
from expanded_deals
group by goal

E se você quiser incluir todas as quatro metas, mesmo que elas não apareçam em nenhum dos deal_goal s, em seguida, basta lançar um LEFT JOIN para dizer isso:
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

Demonstração de SQL :http://sqlfiddle.com/#!15/3f0af/20

Jogue um desses em um select_rows ligue e você obterá seus dados:
Deal.connection.select_rows(%q{ SQL goes here }).each do |row|
  goal = row.first
  n    = row.last.to_i
  #....
end

Provavelmente há muita coisa acontecendo aqui que você não conhece, então vou explicar um pouco.

Em primeiro lugar, estou usando WITH e Common Table Expressions (CTE) para simplificar os SELECTs. COM é um recurso SQL padrão que permite produzir macros SQL ou tabelas temporárias embutidas de uma espécie. Na maioria das vezes, você pode pegar o CTE e soltá-lo diretamente na consulta onde está o nome:
with some_cte(colname1, colname2, ...) as ( some_pile_of_complexity )
select * from some_cte

é como isso:
select * from ( some_pile_of_complexity ) as some_cte(colname1, colname2, ...)

CTEs são a maneira SQL de refatorar uma consulta/método excessivamente complexo em partes menores e mais fáceis de entender.

unnest é uma função de matriz que descompacta uma matriz em linhas individuais. Então, se você disser unnest(ARRAY[1,2]) , você obtém duas linhas de volta:1 e 2 .

VALORES no PostgreSQL é usado para, mais ou menos, gerar tabelas constantes embutidas. Você pode usar VALUES em qualquer lugar que possa usar uma tabela normal, não é apenas uma sintaxe que você lança em um INSERT para informar ao banco de dados quais valores inserir. Isso significa que você pode dizer coisas como:
select * from (values (1), (2)) as dt

e obtenha as linhas 1 e 2 Fora. Lançar esses VALUES em um CTE torna as coisas agradáveis ​​e legíveis e faz com que pareça com qualquer tabela antiga na consulta final.