Apakah mungkin untuk mencari setiap kolom dari setiap tabel untuk nilai tertentu di PostgreSQL?
Pertanyaan serupa tersedia di sini untuk Oracle.
postgresql
grep
string-matching
Sandro Munda
sumber
sumber
Jawaban:
Bagaimana jika membuang konten database, lalu menggunakan
grep
?Utilitas yang sama, pg_dump, dapat menyertakan nama kolom dalam output. Ganti saja
--inserts
ke--column-inserts
. Dengan begitu, Anda juga dapat mencari nama kolom tertentu. Tetapi jika saya mencari nama kolom, saya mungkin akan membuang skema, bukan datanya.sumber
ALTER DATABASE your_db_name SET bytea_output = 'escape';
di database (atau salinannya) sebelum membuangnya. (Saya tidak melihat cara untuk menentukan ini hanya untukpg_dump
perintah.)Berikut adalah fungsi pl / pgsql yang menempatkan record di mana setiap kolom berisi nilai tertentu. Dibutuhkan sebagai argumen nilai yang akan dicari dalam format teks, larik nama tabel untuk ditelusuri (default untuk semua tabel) dan larik nama skema (default semua nama skema).
Ini mengembalikan struktur tabel dengan skema, nama tabel, nama kolom dan kolom semu
ctid
(lokasi fisik baris yang tidak tahan lama dalam tabel, lihat Kolom Sistem )Lihat juga versi di github berdasarkan prinsip yang sama tetapi menambahkan beberapa peningkatan kecepatan dan pelaporan.
Contoh penggunaan dalam database pengujian:
Varian
Untuk menguji dengan ekspresi reguler alih-alih persamaan ketat, seperti grep, ini bagian dari kueri:
SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L
dapat diubah menjadi:
SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L
Untuk perbandingan tidak peka huruf besar / kecil, Anda dapat menulis:
SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)
sumber
~*
lebih memadai daripada lebih rendah (). Tapi bagaimanapunt.*
itu bukan bagian dari jawaban di atas. Mencari kolom demi kolom tidak sama dengan mencari baris sebagai nilai karena pemisah kolom.Ini tidak menentukan cara mencocokkan dengan tepat.
Juga tidak menentukan apa yang harus dikembalikan dengan tepat.
Asumsi:
regclass
) dan tuple ID (ctid
), karena itu paling sederhana.Berikut ini cara sederhana, cepat dan sedikit kotor:
Panggilan:
Berikan pola pencarian tanpa melampirkan
%
.Kenapa agak kotor?
Jika pemisah dan dekorator untuk baris dalam
text
representasi dapat menjadi bagian dari pola penelusuran, mungkin terdapat kesalahan positif:,
secara default()
"
\
dapat ditambahkan sebagai escape charDan representasi teks dari beberapa kolom mungkin bergantung pada pengaturan lokal - tetapi ambiguitas itu melekat pada pertanyaan, bukan pada solusi saya.
Setiap baris kualifikasi dikembalikan sekali saja, meskipun cocok beberapa kali (berbeda dengan jawaban lain di sini).
Ini mencari seluruh DB kecuali katalog sistem. Biasanya akan membutuhkan waktu lama untuk menyelesaikannya . Anda mungkin ingin membatasi ke skema / tabel tertentu (atau bahkan kolom) seperti yang ditunjukkan dalam jawaban lain. Atau tambahkan pemberitahuan dan indikator kemajuan, juga ditunjukkan dalam jawaban lain.
The
regclass
jenis objek identifier direpresentasikan sebagai nama tabel, skema-kualifikasi di mana diperlukan untuk disambiguate sesuai dengan saat inisearch_path
:Apa itu
ctid
?Anda mungkin ingin melepaskan karakter dengan arti khusus dalam pola pencarian. Lihat:
sumber
Dan jika seseorang berpikir itu bisa membantu. Berikut adalah fungsi @Daniel Vérité, dengan parameter lain yang menerima nama kolom yang dapat digunakan dalam pencarian. Dengan cara ini mengurangi waktu pemrosesan. Setidaknya dalam pengujian saya itu berkurang banyak.
Di bawah ini adalah contoh penggunaan fungsi_penelusuran yang dibuat di atas.
sumber
Tanpa menyimpan prosedur baru, Anda dapat menggunakan blok kode dan mengeksekusi untuk mendapatkan tabel kejadian. Anda dapat memfilter hasil berdasarkan skema, tabel atau nama kolom.
sumber
Ada cara untuk mencapai ini tanpa membuat fungsi atau menggunakan alat eksternal. Dengan menggunakan
query_to_xml()
fungsi Postgres yang dapat secara dinamis menjalankan kueri di dalam kueri lain, dimungkinkan untuk mencari teks di banyak tabel. Ini didasarkan pada jawaban saya untuk mengambil rowcount untuk semua tabel :Untuk mencari string
foo
di semua tabel dalam skema, berikut ini dapat digunakan:Perhatikan bahwa penggunaan
xmltable
membutuhkan Postgres 10 atau yang lebih baru. Untuk versi Postgres yang lebih lama, ini juga dapat dilakukan dengan menggunakan xpath ().Ekspresi tabel umum (
WITH ...
) hanya digunakan untuk kenyamanan. Ini loop melalui semua tabel dalampublic
skema. Untuk setiap tabel, kueri berikut ini dijalankan melaluiquery_to_xml()
fungsi:Klausa where digunakan untuk memastikan pembuatan konten XML yang mahal hanya dilakukan untuk baris yang berisi string pencarian. Ini mungkin mengembalikan sesuatu seperti ini:
Konversi dari baris lengkap menjadi
jsonb
dilakukan, sehingga pada hasilnya dapat dilihat nilai mana yang termasuk dalam kolom mana.Di atas mungkin mengembalikan sesuatu seperti ini:
Contoh online untuk Postgres 10+
Contoh online untuk versi Postgres yang lebih lama
sumber
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()
fungsiBerikut fungsi @Daniel Vérité dengan fungsi pelaporan kemajuan. Ini melaporkan kemajuan dalam tiga cara:
_
sumber
- Fungsi di bawah ini akan menampilkan semua tabel yang berisi string tertentu dalam database
--Iterasi melalui semua tabel di database
- Mengembalikan hitungan tabel yang syaratnya terpenuhi. - Misalnya, jika teks yang dimaksud ada di salah satu bidang tabel, - maka jumlahnya akan lebih besar dari 0. Kita dapat menemukan notifikasi - di bagian Pesan dari penampil hasil di database postgres.
--Dapatkan bidang dari setiap tabel. Membangun klausa where dengan semua kolom tabel.
sumber