AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 242101
Accepted
OrangeDog
OrangeDog
Asked: 2019-07-05 07:21:10 +0800 CST2019-07-05 07:21:10 +0800 CST 2019-07-05 07:21:10 +0800 CST

Vários agregados com junção cruzada (lateral)

  • 772

Seguindo combinando array_agg e unnest , dados estes dados:

key |  a | b | c
------------------
 1  |  0 | 1 | {1,2}
 1  |  1 | 2 | {3}
 1  | -1 | 3 | {2}
 1  |  2 | 4 | {}

Executando esta consulta:

SELECT 
  d.key,
  min(d.a) AS a,
  sum(d.b) AS b,
  array_agg(DISTINCT x.c) AS c 
FROM data AS d
  CROSS JOIN LATERAL unnest(d.c) AS x(c)
GROUP BY d.key

Dá o resultado inesperado:

key |  a | b | c
------------------
 1  | -1 | 7 | {1,2,3}

O que está acontecendo aqui, e como obter a soma correta?


Desempenho da resposta

Em meus dados reais (16.642 linhas, 1.942 chaves, 6 agregados), recebo essas estimativas de custo para cada solução sugerida.

  • a_horse_with_no_name opção 1:1761.12..49370.52
  • a_horse_with_no_name opção 2:0.57..89214.72
  • Erwin Brandstetter :1761.12..49370.61
postgresql join
  • 2 2 respostas
  • 1751 Views

2 respostas

  • Voted
  1. Best Answer
    a_horse_with_no_name
    2019-07-05T07:59:08+08:002019-07-05T07:59:08+08:00

    O desaninhamento gera 2 linhas para (chave = 1, a = 0, b = 1) e a junção cruzada remove a linha com a matriz vazia.

    Portanto, seu grupo opera no seguinte conjunto:

    key | a  | b | c
    ----+----+---+--
      1 |  0 | 1 | 1
      1 |  0 | 1 | 2
      1 |  1 | 2 | 3
      1 | -1 | 3 | 2
    

    Uma solução é combinar duas consultas agrupadas por consultas, cada uma agrupando em um nível diferente:

    select *
    from (
      select d1."key", min(d1.a), sum(d1.b)
      from data d1
      group by d1."key"
    ) m
      join (
        select "key", array_agg(DISTINCT x.c) AS c 
        from data d2
          left join lateral unnest(d2.c) as x(c) on true
        where x.c is not null
        group by "key"
      ) a on a."key" = m."key";
    

    Outra abordagem é incluir apenas a "primeira linha" para cada grupo "não aninhado" nos agregados:

    select d."key", 
           min(d.a) filter (where idx = 1 or idx is null), 
           sum(d.b) filter (where idx = 1 or idx is null),
           array_agg(distinct x.c)
    from data AS d
      left join lateral unnest(d.c) with ordinality  AS x(c,idx) on true
    group by d."key";
    

    with ordinalityretorna a posição do elemento não aninhado na matriz original. Para a linha com a matriz vazia, isso será nulo.

    • 1
  2. Erwin Brandstetter
    2019-07-05T08:08:39+08:002019-07-05T08:08:39+08:00

    Um problema com sua consulta é que CROSS JOINelimina linhas onde unnest()não produz linhas (acontece para o array vazio {}).

    Você pode corrigir isso com LEFT JOIN .. ON true, mas o outro problema é que as linhas são multiplicadas onde unnest()retorna várias linhas (acontece para {1,2}).

    É assim que você obtém 7a soma: 1 + 1 + 2 + 3.

    Unir duas subconsultas separadas pode ser mais simples/rápido:

    SELECT *
    FROM (
       SELECT key, min(a) AS min_a, sum(b) AS sum_b
       FROM   data
       GROUP  BY 1
       ) x
    JOIN  (
       SELECT key, array_agg(DISTINCT e) AS dist_c 
       FROM   data, unnest(c) e
       GROUP  BY 1
       ) y USING (key);
    

    A junção simples funciona porque ambas as subconsultas foram agrupadas pela mesma coluna - e contanto que keyseja NOT NULL.

    db<>fique aqui

    Relacionado:

    • Dois SQL LEFT JOINS produzem resultado incorreto
    • 0

relate perguntas

  • Qual é a diferença entre um INNER JOIN e um OUTER JOIN?

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Como é a saída de uma instrução JOIN?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve