Czy można przeszukać każdą kolumnę każdej tabeli pod kątem określonej wartości w PostgreSQL?
Podobne pytanie jest dostępne tutaj dla Oracle.
postgresql
grep
string-matching
Sandro Munda
źródło
źródło
Odpowiedzi:
Co powiesz na zrzucenie zawartości bazy danych, a następnie użycie
grep
?To samo narzędzie, pg_dump, może zawierać nazwy kolumn w danych wyjściowych. Po prostu zmień
--inserts
na--column-inserts
. W ten sposób możesz również wyszukiwać określone nazwy kolumn. Ale gdybym szukał nazw kolumn, prawdopodobnie zrzuciłbym schemat zamiast danych.źródło
ALTER DATABASE your_db_name SET bytea_output = 'escape';
z bazy danych (lub jej kopii) przed jej zrzuceniem. (Nie widzę sposobu, aby określić to tylko dlapg_dump
polecenia.)Oto funkcja pl / pgsql, która lokalizuje rekordy, w których każda kolumna zawiera określoną wartość. Jako argumenty przyjmuje wartość do przeszukania w formacie tekstowym, tablicę nazw tabel do przeszukania (domyślnie wszystkie tabele) i tablicę nazw schematów (domyślnie wszystkie nazwy schematów).
Zwraca strukturę tabeli ze schematem, nazwą tabeli, nazwą kolumny i pseudokolumną
ctid
(nietrwała fizyczna lokalizacja wiersza w tabeli, patrz Kolumny systemowe )Zobacz także wersję na github opartą na tej samej zasadzie, ale dodającą pewne ulepszenia szybkości i raportowania.
Przykłady użycia w testowej bazie danych:
Warianty
Aby przetestować pod kątem wyrażenia regularnego zamiast ścisłej równości, takiej jak grep, ta część zapytania:
SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L
można zmienić na:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
W przypadku porównań bez rozróżniania wielkości liter możesz napisać:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
źródło
~*
bardziej odpowiedni niż niższy (). Ale tak czy inaczej,t.*
nie jest częścią powyższej odpowiedzi. Wyszukiwanie kolumna po kolumnie to nie to samo, co wyszukiwanie wiersza jako wartości ze względu na separatory kolumn.To nie określa, jak dokładnie dopasować.
Nie definiuje też dokładnie, co zwrócić.
Zarozumiały:
regclass
) i identyfikator krotki (ctid
), ponieważ to jest najprostsze.Oto martwy prosty, szybki i nieco brudny sposób:
Połączenie:
Podaj wzorzec wyszukiwania bez zamykania
%
.Dlaczego lekko zabrudzony?
Jeśli separatory i dekoratory wiersza w
text
reprezentacji mogą być częścią wzorca wyszukiwania, mogą występować fałszywe alarmy:,
domyślnie()
"
\
można dodać jako znak zmiany znaczeniaA tekstowa reprezentacja niektórych kolumn może zależeć od lokalnych ustawień - ale ta niejednoznaczność jest nieodłącznym elementem pytania, a nie mojego rozwiązania.
Każdy kwalifikujący się wiersz jest zwracany tylko raz , nawet jeśli pasuje wiele razy (w przeciwieństwie do innych odpowiedzi tutaj).
Przeszukuje całą bazę danych z wyjątkiem katalogów systemowych. Zwykle trwa to długo . Możesz chcieć ograniczyć się do niektórych schematów / tabel (lub nawet kolumn), jak pokazano w innych odpowiedziach. Lub dodaj powiadomienia i wskaźnik postępu, również pokazane w innej odpowiedzi.
regclass
Typ identyfikator obiektu jest reprezentowany jako nazwa tabeli, schematu wykwalifikowanych gdzie konieczne disambiguate według obecnegosearch_path
:Co to jest
ctid
?Możesz chcieć zmienić znaczenie znaków o specjalnym znaczeniu we wzorcu wyszukiwania. Widzieć:
źródło
A jeśli ktoś pomyśli, że to mogłoby pomóc. Oto funkcja @Daniel Vérité z innym parametrem, który akceptuje nazwy kolumn, których można użyć w wyszukiwaniu. W ten sposób skraca czas przetwarzania. Przynajmniej w moim teście znacznie się zmniejszyło.
Poniżej znajduje się przykład użycia funkcji search_function utworzonej powyżej.
źródło
Bez zapisywania nowej procedury możesz użyć bloku kodu i wykonać, aby uzyskać tabelę zdarzeń. Możesz filtrować wyniki według schematu, tabeli lub nazwy kolumny.
źródło
Można to osiągnąć bez tworzenia funkcji lub korzystania z zewnętrznego narzędzia. Używając funkcji Postgresa,
query_to_xml()
która może dynamicznie uruchamiać zapytanie wewnątrz innego zapytania, możliwe jest przeszukiwanie tekstu w wielu tabelach. Jest to oparte na mojej odpowiedzi, aby pobrać liczbę wierszy dla wszystkich tabel :Aby wyszukać ciąg
foo
we wszystkich tabelach w schemacie, można użyć następujących metod:Zauważ, że użycie
xmltable
wymaga Postgres 10 lub nowszego. W przypadku starszych wersji Postgres można to również zrobić za pomocą xpath ().Typowe wyrażenie tabeli (
WITH ...
) jest używane tylko dla wygody. Przechodzi przez wszystkie tabele wpublic
schemacie. Dla każdej tabeli przezquery_to_xml()
funkcję jest wykonywane następujące zapytanie :Klauzula where służy do upewnienia się, że kosztowne generowanie zawartości XML jest wykonywane tylko dla wierszy zawierających wyszukiwany ciąg. To może zwrócić coś takiego:
jsonb
Wykonywana jest konwersja całego wiersza na , dzięki czemu w wyniku można zobaczyć, która wartość należy do której kolumny.Powyższe może zwrócić coś takiego:
Przykład online dla Postgres 10+
Przykład online dla starszych wersji Postgres
źródło
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()
funkcjiOto funkcja @Daniel Vérité z funkcją raportowania postępów. Informuje o postępach na trzy sposoby:
_
źródło
- Funkcja poniżej wyświetli listę wszystkich tabel, które zawierają określony ciąg w bazie danych
- wykonuje iterację po wszystkich tabelach w bazie danych
- Zwraca liczbę tabel, dla których warunek jest spełniony. - Na przykład, jeśli zamierzony tekst istnieje w którymkolwiek z pól tabeli, - wtedy liczba będzie większa od 0. Powiadomienia możemy znaleźć w sekcji Wiadomości przeglądarki wyników w bazie danych postgres.
- Pobierz pola każdej tabeli. Tworzy klauzulę where ze wszystkimi kolumnami tabeli.
źródło