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 / 337927
Accepted
Erasmose
Erasmose
Asked: 2024-03-22 07:13:32 +0800 CST2024-03-22 07:13:32 +0800 CST 2024-03-22 07:13:32 +0800 CST

Quando um índice é criado a partir de uma função em uma coluna, obtemos o nome da função em vez do nome da coluna em pg_attribute no Postgres. Como corrigi-lo?

  • 772

Eu criei a seguinte consulta para obter o nome da tabela, index_type, operator_classes e exclusividade dos índices com base nas respostas principalmente de @Erwin Brandstetter:

SELECT i.indrelid::regclass::text AS table
     , c.relname AS index_name
     , a.amname AS index_type
     , opc.operator_classes
     , i.indisunique AS is_unique
     , array_agg(att.attname) as column_names
FROM   pg_catalog.pg_namespace n
JOIN   pg_catalog.pg_class     c ON c.relnamespace = n.oid
JOIN   pg_catalog.pg_attribute att ON att.attrelid = c.oid
JOIN   pg_catalog.pg_index     i ON i.indexrelid = c.oid
JOIN   pg_catalog.pg_am        a ON a.oid = c.relam
CROSS  JOIN LATERAL (
   SELECT ARRAY (SELECT opc.opcname
                 FROM   unnest(i.indclass::oid[]) WITH ORDINALITY o(oid, ord)
                 JOIN   pg_opclass opc ON opc.oid = o.oid
                 ORDER  BY o.ord)
   ) opc(operator_classes)
WHERE  n.nspname !~ '^pg_'
AND    c.relkind = ANY (ARRAY['r', 't', 'i'])
group by
   i.indrelid, c.relname, a.amname, opc.operator_classes, i.indisunique
ORDER  BY 1, 2, 3, 4;

Isso funciona muito bem, exceto que retorna nomes de colunas errados quando o índice é criado pela transformação de dados de outra coluna. Por exemplo, com o seguinte índice:

CREATE INDEX _ixtr_luxury_inventory_images ON public.luxury_inventory
 USING gin (f_textarr2text(images) gin_trgm_ops)

retorna:

table            | luxury_inventory
index_name       | _ixtr_luxury_inventory_images
index_type       | gin
operator_classes | ['gin_trgm_ops']
is_unique        | False
column_names     | ['f_textarr2text']

Obtemos f_textarr2texto nome da coluna em vez de images.

Como podemos obter os column_names corretos? Estou no Postgres 16.2, se isso importa.

Atualização: Aqui está o SQL de criação da tabela:

create table "luxury_inventory" (
id bigserial primary key,
images text[])

CREATE OR REPLACE FUNCTION "public".f_textarr2text(text[]) 
RETURNS text LANGUAGE sql IMMUTABLE AS $$SELECT array_to_string($1, ',')$$;
postgresql
  • 2 2 respostas
  • 44 Views

2 respostas

  • Voted
  1. Best Answer
    Jeff Vermeer
    2024-03-23T01:48:48+08:002024-03-23T01:48:48+08:00

    Pensando nisso por um momento, talvez seja melhor do que pg_get_indexdefextrair ordinais da coluna indexprsanotada na primeira resposta e, especificamente, do varattnocampo.

    regexp_matchessobre os 'indexprs' (convertendo pg_tree_nodepara text) para varattno)

    Juntei o seguinte, voltando à definição na columnstabela de information_schema:

    SELECT (SELECT JSON_AGG(columns.column_name)
              FROM information_schema.columns
             WHERE table_schema = 'public'
               AND table_name   = i.indrelid::regclass::text
               AND ordinal_position IN (SELECT matches[1]::INTEGER 
                                        FROM regexp_matches(i.indexprs::TEXT,
                                                            'varattno (\d)',
                                                            'g') as matches)) AS argument_columns
         , pg_get_indexdef(att.attrelid, att.attnum, true) 
         , i.indrelid::regclass::text AS table
         , c.relname AS index_nameq
         , att.attname as column_names
    FROM   pg_catalog.pg_namespace n
    JOIN   pg_catalog.pg_class     c ON c.relnamespace = n.oid
    JOIN   pg_catalog.pg_attribute att ON att.attrelid = c.oid
    JOIN   pg_catalog.pg_index     i ON i.indexrelid = c.oid
    WHERE  n.nspname !~ '^pg_'
    AND    c.relkind IN ('r', 't', 'i')
    

    e isso produz:

    argumentos_colunas pg_get_indexdef mesa index_nameq nomes_colunas
    NULO conteúdo_tsv arquivo_lookup_16k fl_16k_tsv_idx conteúdo_tsv
    NULO conteúdo_tsv arquivo_lookup_4k fl_4k_tsv_idx conteúdo_tsv
    NULO id_do_arquivo arquivo_lookup_4k índice_data id_do_arquivo
    ["id_do_arquivo"] abs(id_arquivo) arquivo_lookup_4k índice_data2 abdômen
    ["sequência_não"] round(sequence_no::precisão dupla) arquivo_lookup_4k índice_data3 redondo
    ["sequência_não"] round(sequence_no::precisão dupla) arquivo_lookup_4k índice_data4 redondo
    ["contente"] "substring"(conteúdo, 1, 5) arquivo_lookup_4k índice_data5 substring
    ["file_id", "sequence_no"] abs(file_id - sequência_no) arquivo_lookup_4k índice_data6 abdômen
    NULO conteúdo_tsv arquivo_lookup_8k fl_8k_tsv_idx conteúdo_tsv

    Sinto que isso está muito mais de acordo com o que ambos desejaríamos.

    Observe que:

    • Juntei-me apenas à attnamemesa, porque isso é tudo que preciso
    • JSON_AGG(columns.column_name)pode ser substituído por JSON_AGG(columns.*)ou algo semelhante para selecionar a linha inteira para as colunas.
    • ANY (ARRAY['r', 't', 'i']foi atualizado paraIN ANY ('r', 't', 'i')

    EDITAR:

    Para trazer isso para uma única coluna, vamos COALESCE, e sempre que a nova função retornar NULL, inseriremos um array contendo o resultado de pg_get_indexdef, e ARRAY_AGGpreferimos JSON_AGG. Todos juntos:

    SELECT COALESCE((SELECT ARRAY_AGG(columns.column_name)
                     FROM information_schema.columns
                    WHERE table_schema = 'public'
                      AND table_name   = i.indrelid::regclass::text
                      AND ordinal_position IN (SELECT matches[1]::INTEGER 
                                               FROM regexp_matches(i.indexprs::TEXT,
                                                     'varattno (\d)',
                                                     'g') as matches)), 
                    ARRAY[(pg_get_indexdef(att.attrelid, att.attnum, true))]) AS argument_columns
         , i.indrelid::regclass::text AS table
         , c.relname AS index_nameq
         , att.attname as column_names
    FROM   pg_catalog.pg_namespace n
    JOIN   pg_catalog.pg_class     c ON c.relnamespace = n.oid
    JOIN   pg_catalog.pg_attribute att ON att.attrelid = c.oid
    JOIN   pg_catalog.pg_index     i ON i.indexrelid = c.oid
    WHERE  n.nspname !~ '^pg_'
    AND    c.relkind IN ('r', 't', 'i');
    

    Isso produz:

    argumentos_colunas mesa index_nameq nomes_colunas
    {id_do_arquivo} arquivo_lookup_4k índice_data id_do_arquivo
    {id_do_arquivo} arquivo_lookup_4k índice_data2 abdômen
    {sequence_no} arquivo_lookup_4k índice_data3 redondo
    {sequence_no} arquivo_lookup_4k índice_data4 redondo
    {contente} arquivo_lookup_4k índice_data5 substring
    {file_id, sequência_no} arquivo_lookup_4k índice_data6 abdômen
    • 1
  2. Jeff Vermeer
    2024-03-22T11:15:24+08:002024-03-22T11:15:24+08:00

    Tente pg_get_indexdef, assim:

    SELECT pg_get_indexdef(att.attrelid, att.attnum, true)
    FROM   pg_catalog.pg_namespace n
    JOIN   pg_catalog.pg_class     c ON c.relnamespace = n.oid
    JOIN   pg_catalog.pg_attribute att ON att.attrelid = c.oid
    JOIN   pg_catalog.pg_index     i ON i.indexrelid = c.oid
    JOIN   pg_catalog.pg_am        a ON a.oid = c.relam
    CROSS  JOIN LATERAL (
       SELECT ARRAY (SELECT opc.opcname
                     FROM   unnest(i.indclass::oid[]) WITH ORDINALITY o(oid, ord)
                     JOIN   pg_opclass opc ON opc.oid = o.oid
                     ORDER  BY o.ord)
       ) opc(operator_classes)
    WHERE  n.nspname !~ '^pg_'
    AND    c.relkind = ANY (ARRAY['r', 't', 'i']);
    
    pg_get_indexdef
    "substring"(conteúdo, 1, 5)
    abs(id_arquivo)
    filho_id
    conteúdo_tsv
    conteúdo_tsv
    conteúdo_tsv
    pai_id
    id_do_arquivo
    id_do_arquivo
    classificação_instalada
    round(sequence_no::precisão dupla)
    round(sequence_no::precisão dupla)
    sucesso

    Deve-se lembrar que um índice pode referir-se a múltiplas colunas, e assim uma função pode exigir múltiplas colunas como argumentos.

    Dito isto, recuperando pg_get_indexdefe aplicando um pouco de regexp, podemos obter nossos argumentos

    SELECT (regexp_matches(
             regexp_replace(
                regexp_replace(pg_get_indexdef(att.attrelid, att.attnum, true), 
                               att.attname, 
                               '', 
                               'g'), 
                '^\w|^,|^\:|"', 
                          '', 
                'g'),
             '\((.+)\)'))[1] AS fn_args
         , pg_get_indexdef(att.attrelid, att.attnum, true) 
         , i.indrelid::regclass::text AS table
         , c.relname AS index_name
         , a.amname AS index_type
         , opc.operator_classes
         , i.indisunique AS is_unique
         , att.attname as column_names
    FROM   pg_catalog.pg_namespace n
    JOIN   pg_catalog.pg_class     c ON c.relnamespace = n.oid
    JOIN   pg_catalog.pg_attribute att ON att.attrelid = c.oid
    JOIN   pg_catalog.pg_index     i ON i.indexrelid = c.oid
    JOIN   pg_catalog.pg_am        a ON a.oid = c.relam
    CROSS  JOIN LATERAL (
       SELECT ARRAY (SELECT opc.opcname
                     FROM   unnest(i.indclass::oid[]) WITH ORDINALITY o(oid, ord)
                     JOIN   pg_opclass opc ON opc.oid = o.oid
                     ORDER  BY o.ord)
       ) opc(operator_classes)
    WHERE  n.nspname !~ '^pg_'
    AND    c.relkind = ANY (ARRAY['r', 't', 'i'])
    group by
       i.indrelid, c.relname, a.amname, opc.operator_classes, i.indisunique, att.attrelid, att.attnum
    

    Onde apenas índices definidos com chamadas de função retornam linhas aqui:

    fn_args pg_get_indexdef mesa nome_índice tipo_índice operadores_classes é único nomes_colunas
    conteúdo, 1, 5 "substring"(conteúdo, 1, 5) arquivo_lookup_4k índice_data5 árvore {text_ops} 0 substring
    id_do_arquivo abs(id_arquivo) arquivo_lookup_4k índice_data2 árvore {int4_ops} 0 abdômen
    sequência_no::precisão dupla round(sequence_no::precisão dupla) arquivo_lookup_4k índice_data3 árvore {float8_ops} 0 redondo
    sequência_no::precisão dupla round(sequence_no::precisão dupla) arquivo_lookup_4k índice_data4 árvore {float8_ops} 0 redondo

    Em última análise, você está recuperando o nome da função porque essa chamada de função está sendo usada para construir o índice, e não simplesmente a coluna subjacente.

    Observe a pg_catalog.pg_index.indexprscoluna na sua consulta e você verá algo parecido com o seguinte, que expõe como a função é indexada:

    ({FUNCEXPR :funcid 1342 :funcresulttype 701 :funcretset false :funcvariadic false :funcformat 0 :funccollid 0 :inputcollid 0 
    :args ({FUNCEXPR :funcid 316 :funcresulttype 701 :funcretset false :funcvariadic false :funcformat 2 :funccollid 0 :inputcollid 0 
    :args ({VAR :varno 1 :varattno 2 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnosyn 1 :varattnosyn 2 :location 50}) :location -1}) :location 44})
    
    • 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