É possível pesquisar cada coluna de cada tabela por um valor específico no PostgreSQL?
Uma pergunta semelhante está disponível aqui para a Oracle.
postgresql
grep
string-matching
Sandro Munda
fonte
fonte
Respostas:
Que tal despejar o conteúdo do banco de dados e depois usar
grep
?O mesmo utilitário, pg_dump, pode incluir nomes de colunas na saída. Basta mudar
--inserts
para--column-inserts
. Dessa forma, você também pode pesquisar nomes de coluna específicos. Mas se eu estivesse procurando nomes de colunas, provavelmente descartaria o esquema em vez dos dados.fonte
ALTER DATABASE your_db_name SET bytea_output = 'escape';
no banco de dados (ou uma cópia dele) antes de despejá-lo. (Não estou vendo uma maneira de especificar isso apenas para umpg_dump
comando.)Aqui está uma função pl / pgsql que localiza registros onde qualquer coluna contém um valor específico. Leva como argumentos o valor a ser pesquisado em formato de texto, uma matriz de nomes de tabela a ser pesquisada (o padrão é todas as tabelas) e uma matriz de nomes de esquema (o padrão é todos os nomes de esquema).
Ele retorna uma estrutura de tabela com esquema, nome da tabela, nome da coluna e pseudocoluna
ctid
(localização física não durável da linha na tabela, consulte Colunas do sistema )Veja também a versão no github baseada no mesmo princípio, mas adicionando algumas melhorias de velocidade e relatórios.
Exemplos de uso em um banco de dados de teste:
Variantes
Para testar em uma expressão regular em vez de igualdade estrita, como grep, esta parte da consulta:
SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L
pode ser alterado para:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
Para comparações que não diferenciam maiúsculas de minúsculas, você pode escrever:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
fonte
~*
mais adequado do que lower (). Mas de qualquer maneira, ot.*
não faz parte da resposta acima. Pesquisar coluna por coluna não é o mesmo que pesquisar a linha como um valor por causa dos separadores de coluna.Isso não define como fazer a correspondência exatamente.
Nem define o que retornar exatamente.
Supondo:
regclass
) e o ID da tupla (ctid
), porque é o mais simples.Aqui está um jeito bem simples, rápido e um pouco sujo:
Ligar:
Fornece o padrão de pesquisa sem incluir
%
.Por que um pouco sujo?
Se separadores e decoradores para a linha em
text
representação puderem fazer parte do padrão de pesquisa, pode haver falsos positivos:,
por padrão()
"
\
pode ser adicionado como caractere de escapeE a representação de texto de algumas colunas pode depender das configurações locais - mas essa ambigüidade é inerente à questão, não à minha solução.
Cada linha de qualificação é retornada apenas uma vez , mesmo quando corresponde várias vezes (ao contrário de outras respostas aqui).
Isso pesquisa todo o banco de dados, exceto os catálogos do sistema. Normalmente leva muito tempo para terminar . Você pode querer restringir a certos esquemas / tabelas (ou mesmo colunas) como demonstrado em outras respostas. Ou adicione avisos e um indicador de progresso, também demonstrado em outra resposta.
O
regclass
tipo de identificador de objeto é representado como nome de tabela, qualificado pelo esquema onde necessário para desambiguar de acordo com o atualsearch_path
:O que é
ctid
?Você pode querer escapar caracteres com significado especial no padrão de pesquisa. Vejo:
fonte
E se alguém achar que pode ajudar. Aqui está a função de @Daniel Vérité, com outro parâmetro que aceita nomes de colunas que podem ser usados na pesquisa. Desta forma diminui o tempo de processamento. Pelo menos no meu teste diminuiu muito.
Abaixo está um exemplo de uso da função search_function criada acima.
fonte
Sem armazenar um novo procedimento, você pode usar um bloco de código e executar para obter uma tabela de ocorrências. Você pode filtrar os resultados por esquema, tabela ou nome de coluna.
fonte
Existe uma maneira de fazer isso sem criar uma função ou usar uma ferramenta externa. Usando a
query_to_xml()
função do Postgres, que pode executar dinamicamente uma consulta dentro de outra consulta, é possível pesquisar um texto em muitas tabelas. Isso se baseia em minha resposta para recuperar o número de linhas para todas as tabelas :Para pesquisar a string
foo
em todas as tabelas em um esquema, o seguinte pode ser usado:Observe que o uso de
xmltable
requer Postgres 10 ou mais recente. Para versões anteriores do Postgres, isso também pode ser feito usando xpath ().A expressão de tabela comum (
WITH ...
) é usada apenas por conveniência. Ele percorre todas as tabelas dopublic
esquema. Para cada tabela, a seguinte consulta é executada por meio daquery_to_xml()
função:A cláusula where é usada para garantir que a geração cara de conteúdo XML seja feita apenas para linhas que contêm a string de pesquisa. Isso pode retornar algo assim:
É feita a conversão da linha completa em
jsonb
, para que no resultado se possa ver qual valor pertence a qual coluna.O texto acima pode retornar algo assim:
Exemplo online para Postgres 10+
Exemplo online para versões mais antigas do Postgres
fonte
ERROR: 42883: function format("unknown", information_schema.sql_identifier, information_schema.sql_identifier) does not exist
format('%I.%I', table_schema::text, table_name::text)
ERROR: 42883: function format("unknown", character varying, character varying) does not exist
format()
funçãoAqui está a função de @Daniel Vérité com funcionalidade de relatório de progresso. Ele relata o progresso de três maneiras:
_
fonte
- A função abaixo irá listar todas as tabelas que contêm uma string específica no banco de dados
--Itra através de todas as tabelas no banco de dados
- Retorna a contagem de tabelas para as quais a condição é atendida. - Por exemplo, se o texto pretendido existe em qualquer um dos campos da tabela, - então a contagem será maior que 0. Podemos encontrar as notificações - na seção Mensagens do visualizador de resultados no banco de dados postgres.
--Obter os campos de cada tabela. Constrói a cláusula where com todas as colunas de uma tabela.
fonte