Est-il possible de rechercher dans chaque colonne de chaque table une valeur particulière dans PostgreSQL?
Une question similaire est disponible ici pour Oracle.
postgresql
grep
string-matching
Sandro Munda
la source
la source
Réponses:
Que diriez-vous de vider le contenu de la base de données, puis de l'utiliser
grep
?Le même utilitaire, pg_dump, peut inclure des noms de colonne dans la sortie. Changez simplement
--inserts
pour--column-inserts
. De cette façon, vous pouvez également rechercher des noms de colonnes spécifiques. Mais si je cherchais des noms de colonnes, je viderais probablement le schéma au lieu des données.la source
ALTER DATABASE your_db_name SET bytea_output = 'escape';
sur la base de données (ou une copie de celle-ci) avant de le vider. (Je ne vois pas de moyen de spécifier cela uniquement pour unepg_dump
commande.)Voici une fonction pl / pgsql qui localise les enregistrements où toute colonne contient une valeur spécifique. Il prend comme arguments la valeur à rechercher au format texte, un tableau de noms de table à rechercher (par défaut sur toutes les tables) et un tableau de noms de schéma (par défaut tous les noms de schéma).
Il renvoie une structure de table avec schéma, nom de table, nom de colonne et pseudo-colonne
ctid
(emplacement physique non durable de la ligne dans la table, voir Colonnes système )Voir aussi la version sur github basée sur le même principe mais en ajoutant quelques améliorations de vitesse et de reporting.
Exemples d'utilisation dans une base de données de test:
Variantes
Pour tester par rapport à une expression régulière au lieu de l'égalité stricte, comme grep, cette partie de la requête:
SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L
peut être changé en:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
Pour les comparaisons insensibles à la casse, vous pouvez écrire:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
la source
~*
plus adéquate que lower (). Mais de toute façon, celat.*
ne fait pas partie de la réponse ci-dessus. La recherche colonne par colonne n'est pas la même chose que la recherche de la ligne en tant que valeur en raison des séparateurs de colonnes.Cela ne définit pas comment faire correspondre exactement.
Il ne définit pas non plus ce qu'il faut renvoyer exactement.
En supposant:
regclass
) et l'ID de tuple (ctid
), car c'est le plus simple.Voici un moyen simple, rapide et légèrement sale:
Appel:
Fournissez le modèle de recherche sans inclure
%
.Pourquoi un peu sale?
Si les séparateurs et les décorateurs de la ligne dans la
text
représentation peuvent faire partie du modèle de recherche, il peut y avoir des faux positifs:,
par défaut()
"
\
peut être ajouté comme caractère d'échappementEt la représentation textuelle de certaines colonnes peut dépendre des paramètres locaux - mais cette ambiguïté est inhérente à la question, pas à ma solution.
Chaque ligne de qualification est renvoyée une seule fois , même si elle correspond plusieurs fois (par opposition aux autres réponses ici).
Ceci recherche l'ensemble de la base de données à l'exception des catalogues système. Prendra généralement beaucoup de temps pour terminer . Vous voudrez peut-être vous limiter à certains schémas / tables (ou même à des colonnes) comme illustré dans d'autres réponses. Ou ajoutez des avis et un indicateur de progression, également démontré dans une autre réponse.
Le
regclass
type d'identificateur d'objet est représenté sous forme de nom de table, qualifié de schéma si nécessaire pour lever l'ambiguïté en fonction du courantsearch_path
:Quel est le
ctid
?Vous souhaiterez peut-être échapper des caractères ayant une signification particulière dans le modèle de recherche. Voir:
la source
Et si quelqu'un pense que cela pourrait aider. Voici la fonction de @Daniel Vérité, avec un autre paramètre qui accepte les noms de colonnes utilisables dans la recherche. De cette façon, il réduit le temps de traitement. Au moins dans mon test, il a beaucoup diminué.
Ci-dessous, un exemple d'utilisation de la fonction search_function créée ci-dessus.
la source
Sans stocker une nouvelle procédure, vous pouvez utiliser un bloc de code et exécuter pour obtenir une table des occurrences. Vous pouvez filtrer les résultats par nom de schéma, de table ou de colonne.
la source
Il existe un moyen d'y parvenir sans créer de fonction ni utiliser un outil externe. En utilisant la
query_to_xml()
fonction de Postgres qui peut exécuter dynamiquement une requête dans une autre requête, il est possible de rechercher un texte dans de nombreuses tables. Ceci est basé sur ma réponse pour récupérer le nombre de lignes pour toutes les tables :Pour rechercher la chaîne
foo
dans toutes les tables d'un schéma, les éléments suivants peuvent être utilisés:Notez que l'utilisation de
xmltable
nécessite Postgres 10 ou plus récent. Pour les anciennes versions de Postgres, cela peut également être fait en utilisant xpath ().L'expression de table commune (
WITH ...
) n'est utilisée que par commodité. Il parcourt toutes les tables dupublic
schéma. Pour chaque table, la requête suivante est exécutée via laquery_to_xml()
fonction:La clause where est utilisée pour s'assurer que la génération coûteuse de contenu XML n'est effectuée que pour les lignes contenant la chaîne de recherche. Cela pourrait renvoyer quelque chose comme ceci:
La conversion de la ligne complète en
jsonb
est effectuée, de sorte que dans le résultat, on puisse voir quelle valeur appartient à quelle colonne.Ce qui précède peut renvoyer quelque chose comme ceci:
Exemple en ligne pour Postgres 10+
Exemple en ligne pour les anciennes versions de Postgres
la source
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()
fonctionVoici la fonction de @Daniel Vérité avec la fonctionnalité de rapport de progression. Il rend compte des progrès de trois manières:
_
la source
- La fonction ci-dessous listera toutes les tables qui contiennent une chaîne spécifique dans la base de données
--Itère toutes les tables de la base de données
- Renvoie le nombre de tables pour lesquelles la condition est remplie. - Par exemple, si le texte prévu existe dans l'un des champs de la table, - alors le nombre sera supérieur à 0. Nous pouvons trouver les notifications - dans la section Messages de la visionneuse de résultats dans la base de données postgres.
- Obtenez les champs de chaque table. Construit la clause where avec toutes les colonnes d'une table.
la source