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 / 241541
Accepted
Tim
Tim
Asked: 2019-06-28 05:01:33 +0800 CST2019-06-28 05:01:33 +0800 CST 2019-06-28 05:01:33 +0800 CST

erros json_object_agg em null no nome do campo

  • 772

Versões do PostgreSQL : minha instalação local 11.3 e o violino abaixo está em 10.0. Ambos se comportam da mesma forma.

Eu tenho um esquema de páginas, cada página tem seções e cada seção pode ter um tipo diferente de conteúdo. Quando consulto uma página, desejo exibir tudo o que há sobre essa página em um documento JSON.

Estou usando CTE's para json_agg()vários conteúdos por seção. Finalmente, junto as seções json_object_agg()para mapear os títulos das seções para o conteúdo das seções.

O problema: json_object_agg() gera um erro quando uma página não possui nenhuma seção. Eu verifiquei a culpa usando um regular json_agg()sem títulos de seção. O erro exato:

error: field name must not be null

O que eu quero: Em qualquer caso, não é um erro. Eu não quero fazer tratamento de erros personalizado no lado do receptor. Seria ainda melhor se a consulta pudesse retornar um JSON Nullno lugar do json_object_agg()caso não houvesse seções, mas isso é opcional. (Outras soluções elegantes são bem-vindas)

Os documentos

Provavelmente a documentação está incompleta ou eu perdi alguma coisa. Somente para referência.

Em expressões agregadas diz (ênfase minha):

A maioria das funções de agregação ignora entradas nulas, de modo que as linhas nas quais uma ou mais das expressões produzem nulo são descartadas. Isso pode ser considerado verdadeiro, a menos que especificado de outra forma , para todos os agregados internos.

E em funções agregadas , json_object_agg()sem comentários sobre não manipular null:

agrega pares de nome/valor como um objeto JSON

Fiddle com argumento de domínio defeituoso. Alterar o domínio para as outras opções faz com que funcione bem. Também usar um domínio não existente funciona bem e retorna 0 linhas.

Consulta

with secs as (
    select p.page_id, p.domain, s.section_id as sid, s.title as title
    from pages p
    left join sections s on p.page_id = s.page_id
    where p.domain = 'bar.com'
),
txt as (
    select
        sid,
        json_agg(
            json_build_object(
                'Pos', pos,
                'Text', content
            )
            order by pos asc
        ) as txts
    from texts
    join secs on sid = section_id
    group by sid
),
img as (
    select
        sid,
        json_agg(
            json_build_object(
                'Pos', pos,
                'Image', image
            )
            order by pos asc
        ) as imgs
    from images
    join secs on sid = section_id
    group by sid
)
select
    json_build_object(
        'ID', s.page_id,
        'Domain', domain,
        'Sections', json_object_agg ( -- Error occurs here
            s.title,
            json_build_object(
                'ID', s.sid,
                'Texts', t.txts,
                'Images', i.imgs
            )
            order by s.sid asc
        )
    )
from secs s
left join txt t on s.sid = t.sid
left join img i on s.sid = i.sid
group by s.page_id, domain;

Esquema

create table pages (
    page_id serial primary key,
    domain text unique not null
);

create table sections (
    section_id serial primary key,
    title text not null,
    page_id int references pages
);

create table texts (
    section_id int references sections,
    pos int not null,
    content text not null,
    primary key (section_id, pos)
);

create table images (
    section_id int references sections,
    pos int not null,
    image text not null,
    primary key (section_id, pos)
);

-- spanac.com will have 3 sections with texts and images in each, various amounts
insert into pages (domain) values ('spanac.com');
-- foo.com has 1 empty section
insert into pages (domain) values ('foo.com');
-- bar.com has no sections
insert into pages (domain) values ('bar.com');

-- spanac.com

with s as (
    insert into sections (page_id, title) select page_id, 'first' from pages where domain = 'spanac.com' returning section_id
),
t1 as (
    insert into texts (section_id, pos, content) select section_id, 1, 'spanac one.one' from s
),
t2 as (
    insert into texts (section_id, pos, content) select section_id, 2, 'spanac one.two' from s
),
i1 as (
    insert into images (section_id, pos, image) select section_id, 1, 's11.jpg' from s
)
insert into images (section_id, pos, image) select section_id, 2, 's12.jpg' from s;

with s as (
    insert into sections (page_id, title) select page_id, 'second' from pages where domain = 'spanac.com' returning section_id
),
t1 as (
    insert into texts (section_id, pos, content) select section_id, 1, 'spanac two.one' from s
),
t2 as (
    insert into texts (section_id, pos, content) select section_id, 2, 'spanac two.two' from s
),
i1 as (
    insert into images (section_id, pos, image) select section_id, 1, 's21.jpg' from s
)
insert into images (section_id, pos, image) select section_id, 2, 's22.jpg' from s;

with s as (
    insert into sections (page_id, title) select page_id, 'third' from pages where domain = 'spanac.com' returning section_id
),
t1 as (
    insert into texts (section_id, pos, content) select section_id, 1, 'Spanac three.one' from s
)
insert into images (section_id, pos, image) select section_id, 1, 's31.jpg' from s;

-- foo.com

insert into sections (page_id, title) select page_id, 'empty' from pages where domain = 'foo.com';
postgresql aggregate
  • 4 4 respostas
  • 6894 Views

4 respostas

  • Voted
  1. Best Answer
    Jasen
    2019-06-28T13:51:03+08:002019-06-28T13:51:03+08:00

    Parece que você encontrou um bug.

    Você pode reportá-lo na parte inferior da página inicial deles e monitorar a discussão do bug na lista de discussão pgsql-bugs , eu não espero que eles mudem a maneira como o postgresql lida com esses dados, eles provavelmente apenas corrigirão a documentação.

    Uma possível solução alternativa seria adicionar WHERE s.title IS NOT NULLà consulta de agregação

    select
        json_build_object(
            'ID', s.page_id,
            'Domain', domain,
            'Sections', json_object_agg (
                s.title,
                json_build_object(
                    'ID', s.sid,
                    'Texts', t.txts,
                    'Images', i.imgs
                )
                order by s.sid asc
            )
        )
    from secs s
    left join txt t on s.sid = t.sid
    left join img i on s.sid = i.sid
    WHERE s.title IS NOT NULL -- prevent null title from being agregated.
    group by s.page_id, domain;
    
    • 6
  2. takaomag
    2020-02-12T23:41:00+08:002020-02-12T23:41:00+08:00

    Seria melhor usar FILTER (WHERE ...)e COALESCE(..., '{}'::JSON).

    select
        json_build_object(
            'ID', s.page_id,
            'Domain', domain,
            'Sections', COALESCE(json_object_agg (
                s.title,
                json_build_object(
                    'ID', s.sid,
                    'Texts', t.txts,
                    'Images', i.imgs
                )
                order by s.sid asc
            ) FILTER (WHERE s.title IS NOT NULL), '{}'::JSON)
        )
    from secs s
    left join txt t on s.sid = t.sid
    left join img i on s.sid = i.sid
    group by s.page_id, domain;
    

    Veja violino .

    • 4
  3. chewster
    2020-05-24T10:48:43+08:002020-05-24T10:48:43+08:00

    Eu tive um problema semelhante envolvendo o título dos eventos de treinamento e felizmente encontrei este post. Tomei um tato ligeiramente diferente para manter os registros de título nulo usando coalesce. Dessa forma, a questão dos títulos nulos é visível e pode ser abordada em processos/pipelines de dados upstream.

    Codifique com coalesce para o valor do nome do campo de agregação json_object_agg:

    select
        json_build_object(
            'ID', s.page_id,
            'Domain', domain,
            'Sections', json_object_agg (
                coalesce(s.title, 'Null') as title,
                json_build_object(
                    'ID', s.sid,
                    'Texts', t.txts,
                    'Images', i.imgs
                )
                order by s.sid asc
            )
        )
    from secs s
    left join txt t on s.sid = t.sid
    left join img i on s.sid = i.sid
    group by s.page_id, domain;
    
    • 0
  4. chewster
    2020-05-27T14:45:45+08:002020-05-27T14:45:45+08:00

    Seu código abaixo não retorna os resultados desejados:

    select
        json_build_object(
            'ID', s.page_id,
            'Domain', domain,
            'Sections', COALESCE(json_object_agg (
                s.title,
                json_build_object(
                    'ID', s.sid,
                    'Texts', t.txts,
                    'Images', i.imgs
                )
                order by s.sid asc
            ) FILTER (WHERE s.title IS NOT NULL), '{}'::JSON)
        )
    from secs s
    left join txt t on s.sid = t.sid
    left join img i on s.sid = i.sid
    group by s.page_id, domain;
    

    Se você filtrar o JSON conforme indicado em sua resposta com COALESCE agrupado em torno da chamada json_object_agg, você não obterá uma agregação para registros que tenham um título NULL. Você só obterá uma agregação {} vazia.

    Queremos obter uma agregação para TODOS os registros, incluindo aqueles com títulos NULL. Queremos que seus IDs, Textos e Imagens agregados sejam retornados com um título - mesmo que o título seja 'Nulo'. Isso é alcançado pela minha resposta original abaixo (eu teria simplesmente comentado em sua postagem, mas fui impedido de fazê-lo, então tive que postar novamente esta resposta)

    select
        json_build_object(
            'ID', s.page_id,
            'Domain', domain,
            'Sections', json_object_agg (
                COALESCE(s.title,'Null') as title,
                json_build_object(
                    'ID', s.sid,
                    'Texts', t.txts,
                    'Images', i.imgs
                )
                order by s.sid asc
            ) 
        )
    from secs s
    left join txt t on s.sid = t.sid
    left join img i on s.sid = i.sid
    group by s.page_id, domain;
    
    • 0

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

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

  • 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