Ist es möglich, jede Spalte jeder Tabelle nach einem bestimmten Wert in PostgreSQL zu durchsuchen ?
Eine ähnliche Frage ist hier für Oracle verfügbar .
postgresql
grep
string-matching
Sandro Munda
quelle
quelle
Antworten:
Wie wäre es, den Inhalt der Datenbank zu sichern und dann zu verwenden
grep
?Das gleiche Dienstprogramm, pg_dump, kann Spaltennamen in die Ausgabe aufnehmen. Wechseln Sie einfach
--inserts
zu--column-inserts
. Auf diese Weise können Sie auch nach bestimmten Spaltennamen suchen. Aber wenn ich nach Spaltennamen suchen würde, würde ich wahrscheinlich das Schema anstelle der Daten ausgeben.quelle
ALTER DATABASE your_db_name SET bytea_output = 'escape';
der Datenbank (oder einer Kopie davon) speichern, bevor Sie sie sichern können . (Ich sehe keine Möglichkeit, dies nur für einenpg_dump
Befehl anzugeben .)Hier ist eine pl / pgsql-Funktion , die Datensätze findet, in denen eine Spalte einen bestimmten Wert enthält. Als Argumente werden der zu suchende Wert im Textformat, ein Array von Tabellennamen, nach denen gesucht werden soll (standardmäßig alle Tabellen) und ein Array von Schemanamen (standardmäßig alle Schemanamen) verwendet.
Es gibt eine Tabellenstruktur mit Schema, Name der Tabelle, Name der Spalte und Pseudospalte zurück
ctid
(nicht dauerhafte physische Position der Zeile in der Tabelle, siehe Systemspalten ).Siehe auch die Version auf Github, die auf demselben Prinzip basiert, aber einige Geschwindigkeits- und Berichtsverbesserungen hinzufügt.
Anwendungsbeispiele in einer Testdatenbank:
Varianten
Um diesen Teil der Abfrage anhand eines regulären Ausdrucks anstelle einer strengen Gleichheit wie grep zu testen:
SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L
kann geändert werden in:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
Für Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung können Sie Folgendes schreiben:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
quelle
~*
angemessener als niedriger (). Aber dast.*
ist sowieso nicht Teil der obigen Antwort. Das spaltenweise Suchen ist aufgrund der Spaltentrennzeichen nicht dasselbe wie das Durchsuchen der Zeile als Wert.Dies definiert nicht, wie genau übereinstimmen soll.
Es definiert auch nicht, was genau zurückgegeben werden soll.
Angenommen:
regclass
) und die Tupel-ID (ctid
) zurück, da dies am einfachsten ist.Hier ist eine absolut einfache, schnelle und leicht schmutzige Art:
Anruf:
Geben Sie das Suchmuster ohne Beilage an
%
.Warum etwas schmutzig?
Wenn Trennzeichen und Dekoratoren für die dargestellte Zeile
text
Teil des Suchmusters sein können, kann es zu Fehlalarmen kommen:,
Standardmäßig()
"
\
kann als Escape-Zeichen hinzugefügt werdenUnd die Textdarstellung einiger Spalten hängt möglicherweise von den lokalen Einstellungen ab - aber diese Mehrdeutigkeit ist der Frage inhärent, nicht meiner Lösung.
Jede qualifizierende Zeile wird nur einmal zurückgegeben , auch wenn sie mehrmals übereinstimmt (im Gegensatz zu anderen Antworten hier).
Dadurch wird die gesamte Datenbank mit Ausnahme der Systemkataloge durchsucht. Die Fertigstellung dauert normalerweise lange . Möglicherweise möchten Sie sich auf bestimmte Schemas / Tabellen (oder sogar Spalten) beschränken, wie in anderen Antworten gezeigt. Oder fügen Sie Hinweise und eine Fortschrittsanzeige hinzu, die auch in einer anderen Antwort gezeigt werden.
Der
regclass
Objektkennungstyp wird als Tabellenname dargestellt, der bei Bedarf schemaqualifiziert ist, um gemäß dem aktuellen Wert zu unterscheidensearch_path
:Was ist das
ctid
?Möglicherweise möchten Sie Zeichen mit besonderer Bedeutung im Suchmuster maskieren. Sehen:
quelle
Und wenn jemand denkt, es könnte helfen. Hier ist die Funktion von @Daniel Vérité mit einem weiteren Parameter, der Namen von Spalten akzeptiert, die für die Suche verwendet werden können. Auf diese Weise wird die Verarbeitungszeit verkürzt. Zumindest in meinem Test hat es sich stark reduziert.
Unten ist ein Beispiel für die Verwendung der oben erstellten Suchfunktion.
quelle
Ohne eine neue Prozedur zu speichern, können Sie einen Codeblock verwenden und ausführen, um eine Tabelle mit Vorkommen zu erhalten. Sie können Ergebnisse nach Schema-, Tabellen- oder Spaltennamen filtern.
quelle
Es gibt eine Möglichkeit, dies zu erreichen, ohne eine Funktion zu erstellen oder ein externes Tool zu verwenden. Durch die Verwendung der Postgres-
query_to_xml()
Funktion, mit der eine Abfrage dynamisch in einer anderen Abfrage ausgeführt werden kann, kann ein Text in vielen Tabellen durchsucht werden. Dies basiert auf meiner Antwort , um die Zeilenanzahl für alle Tabellen abzurufen :Um
foo
in allen Tabellen eines Schemas nach der Zeichenfolge zu suchen , können Sie Folgendes verwenden:Beachten Sie, dass für die Verwendung von
xmltable
Postgres 10 oder neuer erforderlich ist. Bei älteren Postgres-Versionen kann dies auch mit xpath () erfolgen.Der allgemeine Tabellenausdruck (
WITH ...
) wird nur zur Vereinfachung verwendet. Es durchläuft alle Tabellen impublic
Schema. Für jede Tabelle wird die folgende Abfrage über diequery_to_xml()
Funktion ausgeführt:Die where-Klausel wird verwendet, um sicherzustellen, dass die teure Generierung von XML-Inhalten nur für Zeilen erfolgt, die die Suchzeichenfolge enthalten. Dies könnte etwa Folgendes zurückgeben:
Die Konvertierung der gesamten Zeile in
jsonb
erfolgt, so dass im Ergebnis zu sehen ist, welcher Wert zu welcher Spalte gehört.Das Obige könnte etwa Folgendes zurückgeben:
Online-Beispiel für Postgres 10+
Online-Beispiel für ältere Postgres-Versionen
quelle
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()
Funktion hatHier ist die Funktion von @Daniel Vérité mit Funktionen zur Fortschrittsberichterstattung. Es gibt Fortschritte auf drei Arten:
_
quelle
- Die folgende Funktion listet alle Tabellen auf, die eine bestimmte Zeichenfolge in der Datenbank enthalten
- Durchläuft alle Tabellen in der Datenbank
- Gibt die Anzahl der Tabellen zurück, für die die Bedingung erfüllt ist. - Wenn beispielsweise der beabsichtigte Text in einem der Felder der Tabelle vorhanden ist, - ist die Anzahl größer als 0. Die Benachrichtigungen finden Sie im Abschnitt "Nachrichten" des Ergebnisbetrachters in der Postgres-Datenbank.
- Holen Sie sich die Felder jeder Tabelle. Erstellt die where-Klausel mit allen Spalten einer Tabelle.
quelle