วิธีค้นหาค่าเฉพาะในตารางทั้งหมด (PostgreSQL)


113

เป็นไปได้ไหมที่จะค้นหา ทุกคอลัมน์ของทุกตารางเพื่อหาค่าเฉพาะใน PostgreSQL

คำถามที่คล้ายกันมีอยู่ที่นี่สำหรับ Oracle


คุณกำลังมองหาเครื่องมือหรือต้องการดำเนินการตามขั้นตอนที่แสดงในคำถามที่เชื่อมโยงหรือไม่?
a_horse_with_no_name

ไม่เป็นวิธีที่ง่ายที่สุดในการค้นหาค่าเฉพาะในฟิลด์ / ตารางทั้งหมด
Sandro Munda

คุณไม่ต้องการใช้เครื่องมือภายนอกหรือไม่?
a_horse_with_no_name

1
ถ้าเป็นวิธีที่ง่ายที่สุด => ตกลงสำหรับเครื่องมือภายนอก :-)
Sandro Munda

คำตอบ:


133

แล้วทิ้งเนื้อหาของฐานข้อมูลแล้วใช้grepอย่างไร?

$ pg_dump --data-only --inserts -U postgres your-db-name > a.tmp
$ grep United a.tmp
INSERT INTO countries VALUES ('US', 'United States');
INSERT INTO countries VALUES ('GB', 'United Kingdom');

ยูทิลิตี้เดียวกัน pg_dump สามารถรวมชื่อคอลัมน์ในเอาต์พุตได้ เพียงแค่เปลี่ยน--insertsเป็น--column-inserts. ด้วยวิธีนี้คุณสามารถค้นหาชื่อคอลัมน์เฉพาะได้เช่นกัน แต่ถ้าฉันกำลังมองหาชื่อคอลัมน์ฉันอาจจะทิ้งสคีมาแทนข้อมูล

$ pg_dump --data-only --column-inserts -U postgres your-db-name > a.tmp
$ grep country_code a.tmp
INSERT INTO countries (iso_country_code, iso_country_name) VALUES ('US', 'United  States');
INSERT INTO countries (iso_country_code, iso_country_name) VALUES ('GB', 'United Kingdom');

5
+1 ฟรีและเรียบง่าย และถ้าคุณต้องการโครงสร้าง pg_dump ก็สามารถทำได้เช่นกัน นอกจากนี้หาก grep ไม่ใช่สิ่งที่คุณใช้เครื่องมือค้นหาเนื้อหาที่คุณต้องการในโครงสร้างและ / หรือข้อมูลที่ถูกทิ้ง
Kuberchaun

หากคุณต้องการ grep text data (ซึ่งโดยทั่วไปจะเข้ารหัสใน postgres เวอร์ชันล่าสุด) คุณอาจต้องALTER DATABASE your_db_name SET bytea_output = 'escape';บนฐานข้อมูล (หรือสำเนา) ก่อนที่จะถ่ายโอนข้อมูล (ฉันไม่เห็นวิธีการที่จะระบุเพียงแค่นี้สำหรับเป็นpg_dumpคำสั่ง.)
Phils

อธิบายรายละเอียดได้ไหม .. ? วิธีค้นหาสตริง 'ABC' ในตารางทั้งหมด?
คุณ Bhosale

1
หากคุณใช้ IntelliJ คุณสามารถคลิกขวาที่ฐานข้อมูลของคุณแล้วเลือก "Dump with" pg_dump "" หรือ "Dump data to file (s)"
Laurens

3
วิธีนี้เป็นวิธีแก้ปัญหาที่ถูกต้องสำหรับฐานข้อมูลใด ๆ ที่มีขนาดใหญ่เพียงพอที่คุณไม่สามารถถ่ายโอนข้อมูลลงในดิสก์ได้
Govind Parmar

78

นี่คือฟังก์ชัน pl / pgsqlที่ค้นหาระเบียนที่คอลัมน์ใด ๆ มีค่าเฉพาะ ใช้เป็นอาร์กิวเมนต์ที่เป็นค่าในการค้นหาในรูปแบบข้อความอาร์เรย์ของชื่อตารางที่จะค้นหา (ค่าเริ่มต้นสำหรับตารางทั้งหมด) และอาร์เรย์ของชื่อสคีมา (ค่าเริ่มต้นของชื่อสคีมาทั้งหมด)

ส่งคืนโครงสร้างตารางที่มีสคีมาชื่อตารางชื่อคอลัมน์และคอลัมน์หลอกctid(ตำแหน่งทางกายภาพที่ไม่คงทนของแถวในตารางโปรดดูคอลัมน์ระบบ )

CREATE OR REPLACE FUNCTION search_columns(
    needle text,
    haystack_tables name[] default '{}',
    haystack_schema name[] default '{}'
)
RETURNS table(schemaname text, tablename text, columnname text, rowctid text)
AS $$
begin
  FOR schemaname,tablename,columnname IN
      SELECT c.table_schema,c.table_name,c.column_name
      FROM information_schema.columns c
        JOIN information_schema.tables t ON
          (t.table_name=c.table_name AND t.table_schema=c.table_schema)
        JOIN information_schema.table_privileges p ON
          (t.table_name=p.table_name AND t.table_schema=p.table_schema
              AND p.privilege_type='SELECT')
        JOIN information_schema.schemata s ON
          (s.schema_name=t.table_schema)
      WHERE (c.table_name=ANY(haystack_tables) OR haystack_tables='{}')
        AND (c.table_schema=ANY(haystack_schema) OR haystack_schema='{}')
        AND t.table_type='BASE TABLE'
  LOOP
    FOR rowctid IN
      EXECUTE format('SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L',
       schemaname,
       tablename,
       columnname,
       needle
      )
    LOOP
      -- uncomment next line to get some progress report
      -- RAISE NOTICE 'hit in %.%', schemaname, tablename;
      RETURN NEXT;
    END LOOP;
 END LOOP;
END;
$$ language plpgsql;

ดูเวอร์ชันบน github ด้วยตามหลักการเดียวกัน แต่เพิ่มการปรับปรุงความเร็วและการรายงานบางอย่าง

ตัวอย่างการใช้งานในฐานข้อมูลทดสอบ:

  • ค้นหาในตารางทั้งหมดภายในสคีมาสาธารณะ:
เลือก * จาก search_columns ('foobar');
 schemaname | ชื่อตาราง | ชื่อคอลัมน์ | rowctid
------------ + ----------- + ------------ + ---------
 สาธารณะ | s3 | ชื่อผู้ใช้ | (0,11)
 สาธารณะ | s2 | relname | (7,29)
 สาธารณะ | w | ร่างกาย | (0,2)
(3 แถว)
  • ค้นหาในตารางเฉพาะ:
 เลือก * จาก search_columns ('foobar', '{w}');
 schemaname | ชื่อตาราง | ชื่อคอลัมน์ | rowctid
------------ + ----------- + ------------ + ---------
 สาธารณะ | w | ร่างกาย | (0,2)
(1 แถว)
  • ค้นหาในตารางย่อยที่ได้รับจากการเลือก:
เลือก * จาก search_columns ('foobar', array (เลือก table_name :: name จาก information_schema.tables โดยที่ table_name เช่น 's%'), array ['public']);
 schemaname | ชื่อตาราง | ชื่อคอลัมน์ | rowctid
------------ + ----------- + ------------ + ---------
 สาธารณะ | s2 | relname | (7,29)
 สาธารณะ | s3 | ชื่อผู้ใช้ | (0,11)
(2 แถว)
  • รับแถวผลลัพธ์พร้อมตารางฐานที่สอดคล้องกันและและ ctid:
เลือก * จาก public.w โดยที่ ctid = '(0,2)';
 ชื่อเรื่อง | ร่างกาย | tsv         
------- + -------- + ---------------------
 toto | foobar | 'foobar': 2 'toto': 1

ตัวแปร

  • ในการทดสอบกับนิพจน์ทั่วไปแทนที่จะเป็นความเท่าเทียมกันอย่างเข้มงวดเช่น grep ส่วนนี้ของแบบสอบถาม:

    SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L

    อาจเปลี่ยนเป็น:

    SELECT ctid FROM %I.%I WHERE cast(%I as text) ~ %L

  • สำหรับการเปรียบเทียบแบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่คุณสามารถเขียน:

    SELECT ctid FROM %I.%I WHERE lower(cast(%I as text)) = lower(%L)


ข้อผิดพลาด: ข้อผิดพลาดทางไวยากรณ์ที่หรือใกล้กับ "ค่าเริ่มต้น" LINE 3: haystack_tables name [] default "{}" (โดยใช้ PostgreSQL 8.2.17 และไม่สามารถอัปเกรดได้)
Henno

@Henno: ใช่มันต้องใช้ PG-9.1 แก้ไขตอนนี้เพื่อให้ชัดเจน หากต้องการใช้กับเวอร์ชันเก่าคุณจะต้องปรับเปลี่ยน
Daniel Vérité

1
@Rajendra_Prasad: ตัวดำเนินการนิพจน์ทั่วไปมีตัวแปรที่ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่: ~*เพียงพอมากกว่าต่ำกว่า () แต่อย่างไรก็ตามt.*ไม่ใช่ส่วนหนึ่งของคำตอบข้างต้น การค้นหาคอลัมน์ตามคอลัมน์ไม่เหมือนกับการค้นหาแถวเป็นค่าเนื่องจากตัวคั่นคอลัมน์
Daniel Vérité

2
สิ่งนี้จะส่งคืนเพียงหนึ่งแถวต่อคอลัมน์ schema-table-column
theGtknerd

1
ขอบคุณมาก. วิธีนี้ใช้ได้ผลดีกับฉัน ฉันต้องหาตารางในรายการมากกว่า 1,000 ตารางซึ่งมี url เฉพาะ คุณช่วยวันของฉัน!.
Sunil

7

เพื่อค้นหาทุกคอลัมน์ของทุกตารางเพื่อหาค่าเฉพาะ

สิ่งนี้ไม่ได้กำหนดวิธีการจับคู่ทั้งหมด
และไม่ได้กำหนดสิ่งที่จะส่งคืนอย่างแน่นอน

สมมติว่า:

  • ค้นหาแถวที่มีคอลัมน์ใดก็ได้ที่มีค่าที่กำหนดในการแสดงข้อความ - ซึ่งตรงข้ามกับการเท่ากับค่าที่กำหนด
  • ส่งคืนชื่อตาราง ( regclass) และรหัสทูเปิล ( ctid) เพราะง่ายที่สุด

นี่คือวิธีที่ง่ายรวดเร็วและสกปรกเล็กน้อย:

CREATE OR REPLACE FUNCTION search_whole_db(_like_pattern text)
  RETURNS TABLE(_tbl regclass, _ctid tid) AS
$func$
BEGIN
   FOR _tbl IN
      SELECT c.oid::regclass
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = relnamespace
      WHERE  c.relkind = 'r'                           -- only tables
      AND    n.nspname !~ '^(pg_|information_schema)'  -- exclude system schemas
      ORDER BY n.nspname, c.relname
   LOOP
      RETURN QUERY EXECUTE format(
         'SELECT $1, ctid FROM %s t WHERE t::text ~~ %L'
       , _tbl, '%' || _like_pattern || '%')
      USING _tbl;
   END LOOP;
END
$func$  LANGUAGE plpgsql;

โทร:

SELECT * FROM search_whole_db('mypattern');

%ให้รูปแบบการค้นหาโดยไม่มีการปิดล้อม

ทำไมสกปรกเล็กน้อย?

หากตัวคั่นและตัวตกแต่งสำหรับแถวที่textเป็นตัวแทนสามารถเป็นส่วนหนึ่งของรูปแบบการค้นหาอาจมีผลบวกปลอม:

  • ตัวคั่นคอลัมน์: ,โดยค่าเริ่มต้น
  • ทั้งแถวอยู่ในวงเล็บ:()
  • ค่าบางค่าอยู่ในเครื่องหมายคำพูดคู่ "
  • \ อาจถูกเพิ่มเป็นอักขระหนี

และการแสดงข้อความของคอลัมน์บางคอลัมน์อาจขึ้นอยู่กับการตั้งค่าในเครื่อง - แต่ความคลุมเครือนั้นมีอยู่ในคำถามไม่ใช่วิธีแก้ปัญหาของฉัน

แต่ละแถวที่มีคุณสมบัติจะถูกส่งคืนเพียงครั้งเดียวแม้ว่าจะตรงกันหลายครั้งก็ตาม (ตรงข้ามกับคำตอบอื่น ๆ ที่นี่)

สิ่งนี้ค้นหา DB ทั้งหมดยกเว้นแค็ตตาล็อกระบบ โดยทั่วไปจะใช้เวลานานที่จะเสร็จสิ้น คุณอาจต้องการ จำกัด เฉพาะสคีมา / ตาราง (หรือแม้แต่คอลัมน์) เหมือนที่แสดงในคำตอบอื่น ๆ หรือเพิ่มการแจ้งเตือนและตัวบ่งชี้ความคืบหน้าซึ่งแสดงให้เห็นในคำตอบอื่น

regclassประเภทระบุวัตถุจะแสดงเป็นชื่อตารางคีที่มีคุณสมบัติที่จำเป็นที่จะต้องกระจ่างตามที่ปัจจุบันsearch_path:

คืออะไรctid?

คุณอาจต้องการหลีกเลี่ยงอักขระที่มีความหมายพิเศษในรูปแบบการค้นหา ดู:


โซลูชันที่ยอดเยี่ยมนี้ดียิ่งขึ้นโดยมี lower () - 'SELECT $ 1, ctid จาก% st WHERE lower (t :: text) ~~ lower (% L)'
Georgi Bonchev

5

และหากมีใครคิดว่ามันสามารถช่วยได้ นี่คือฟังก์ชันของ @Daniel Véritéซึ่งมีพารามิเตอร์อื่นที่ยอมรับชื่อของคอลัมน์ที่สามารถใช้ในการค้นหาได้ วิธีนี้จะช่วยลดเวลาในการประมวลผล อย่างน้อยในการทดสอบของฉันมันก็ลดลงมาก

CREATE OR REPLACE FUNCTION search_columns(
    needle text,
    haystack_columns name[] default '{}',
    haystack_tables name[] default '{}',
    haystack_schema name[] default '{public}'
)
RETURNS table(schemaname text, tablename text, columnname text, rowctid text)
AS $$
begin
  FOR schemaname,tablename,columnname IN
      SELECT c.table_schema,c.table_name,c.column_name
      FROM information_schema.columns c
      JOIN information_schema.tables t ON
        (t.table_name=c.table_name AND t.table_schema=c.table_schema)
      WHERE (c.table_name=ANY(haystack_tables) OR haystack_tables='{}')
        AND c.table_schema=ANY(haystack_schema)
        AND (c.column_name=ANY(haystack_columns) OR haystack_columns='{}')
        AND t.table_type='BASE TABLE'
  LOOP
    EXECUTE format('SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L',
       schemaname,
       tablename,
       columnname,
       needle
    ) INTO rowctid;
    IF rowctid is not null THEN
      RETURN NEXT;
    END IF;
 END LOOP;
END;
$$ language plpgsql;

Bellow เป็นตัวอย่างของการใช้งานฟังก์ชันค้นหาที่สร้างขึ้นด้านบน

SELECT * FROM search_columns('86192700'
    , array(SELECT DISTINCT a.column_name::name FROM information_schema.columns AS a
            INNER JOIN information_schema.tables as b ON (b.table_catalog = a.table_catalog AND b.table_schema = a.table_schema AND b.table_name = a.table_name)
        WHERE 
            a.column_name iLIKE '%cep%' 
            AND b.table_type = 'BASE TABLE'
            AND b.table_schema = 'public'
    )

    , array(SELECT b.table_name::name FROM information_schema.columns AS a
            INNER JOIN information_schema.tables as b ON (b.table_catalog = a.table_catalog AND b.table_schema = a.table_schema AND b.table_name = a.table_name)
        WHERE 
            a.column_name iLIKE '%cep%' 
            AND b.table_type = 'BASE TABLE'
            AND b.table_schema = 'public')
);

5

โดยไม่ต้องจัดเก็บโพรซีเดอร์ใหม่คุณสามารถใช้บล็อกรหัสและดำเนินการเพื่อรับตารางการเกิดขึ้นได้ คุณสามารถกรองผลลัพธ์ตามชื่อสคีมาตารางหรือคอลัมน์

DO $$
DECLARE
  value int := 0;
  sql text := 'The constructed select statement';
  rec1 record;
  rec2 record;
BEGIN
  DROP TABLE IF EXISTS _x;
  CREATE TEMPORARY TABLE _x (
    schema_name text, 
    table_name text, 
    column_name text,
    found text
  );
  FOR rec1 IN 
        SELECT table_schema, table_name, column_name
        FROM information_schema.columns 
        WHERE table_name <> '_x'
                AND UPPER(column_name) LIKE UPPER('%%')                  
                AND table_schema <> 'pg_catalog'
                AND table_schema <> 'information_schema'
                AND data_type IN ('character varying', 'text', 'character', 'char', 'varchar')
        LOOP
    sql := concat('SELECT ', rec1."column_name", ' AS "found" FROM ',rec1."table_schema" , '.',rec1."table_name" , ' WHERE UPPER(',rec1."column_name" , ') LIKE UPPER(''','%my_substring_to_find_goes_here%' , ''')');
    RAISE NOTICE '%', sql;
    BEGIN
        FOR rec2 IN EXECUTE sql LOOP
            RAISE NOTICE '%', sql;
            INSERT INTO _x VALUES (rec1."table_schema", rec1."table_name", rec1."column_name", rec2."found");
        END LOOP;
    EXCEPTION WHEN OTHERS THEN
    END;
  END LOOP;
  END; $$;

SELECT * FROM _x;

คุณระบุสตริงการค้นหาที่ใด หรือนี่เป็นเพียงการทิ้งฐานข้อมูลทั้งหมดแบบตารางต่อตาราง?
jimtut

1
ฉันไม่ได้สร้างพารามิเตอร์สำหรับสตริง คุณสามารถฮาร์ดโค้ดและเรียกใช้เป็นบล็อกหรือสร้างโพรซีเดอร์ที่จัดเก็บจากมัน ไม่ว่าในกรณีใดสตริงของคุณที่จะค้นหาจะอยู่ตรงนี้ระหว่างเครื่องหมายสองเปอร์เซ็นต์: WHERE UPPER (', rec1. "column_name",') LIKE UPPER ('' ',' %% ',' '')
profimedica

5

มีวิธีที่จะบรรลุสิ่งนี้ได้โดยไม่ต้องสร้างฟังก์ชันหรือใช้เครื่องมือภายนอก ด้วยการใช้query_to_xml()ฟังก์ชันPostgres ที่สามารถเรียกใช้แบบสอบถามภายในแบบสอบถามอื่นแบบไดนามิกทำให้สามารถค้นหาข้อความในตารางต่างๆได้ นี่เป็นไปตามคำตอบของฉันในการดึง rowcount สำหรับตารางทั้งหมด :

หากต้องการค้นหาสตริงfooในตารางทั้งหมดในสคีมาสามารถใช้สิ่งต่อไปนี้:

with found_rows as (
  select format('%I.%I', table_schema, table_name) as table_name,
         query_to_xml(format('select to_jsonb(t) as table_row 
                              from %I.%I as t 
                              where t::text like ''%%foo%%'' ', table_schema, table_name), 
                      true, false, '') as table_rows
  from information_schema.tables 
  where table_schema = 'public'
)
select table_name, x.table_row
from found_rows f
  left join xmltable('//table/row' 
                     passing table_rows
                       columns
                         table_row text path 'table_row') as x on true

โปรดทราบว่าการใช้xmltableต้องใช้ Postgres 10 หรือใหม่กว่า สำหรับ Postgres เวอร์ชันเก่าสามารถทำได้โดยใช้ xpath ()

with found_rows as (
  select format('%I.%I', table_schema, table_name) as table_name,
         query_to_xml(format('select to_jsonb(t) as table_row 
                              from %I.%I as t 
                              where t::text like ''%%foo%%'' ', table_schema, table_name), 
                      true, false, '') as table_rows
  from information_schema.tables 
  where table_schema = 'public'
)
select table_name, x.table_row
from found_rows f
   cross join unnest(xpath('/table/row/table_row/text()', table_rows)) as r(data)

นิพจน์ตารางทั่วไป ( WITH ...) ใช้เพื่อความสะดวกเท่านั้น มันวนลูปผ่านตารางทั้งหมดในpublicสคีมา สำหรับแต่ละตารางจะมีการเรียกใช้แบบสอบถามต่อไปนี้ผ่านquery_to_xml()ฟังก์ชัน:

select to_jsonb(t)
from some_table t
where t::text like '%foo%';

ตำแหน่งที่ใช้คำสั่งเพื่อให้แน่ใจว่าการสร้างเนื้อหา XML ที่มีราคาแพงนั้นทำได้สำหรับแถวที่มีสตริงการค้นหาเท่านั้น สิ่งนี้อาจส่งคืนสิ่งนี้:

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
  <table_row>{"id": 42, "some_column": "foobar"}</table_row>
</row>
</table>

การแปลงแถวที่สมบูรณ์jsonbเป็นเสร็จสิ้นดังนั้นในผลลัพธ์จะเห็นว่าค่าใดเป็นของคอลัมน์ใด

ข้างต้นอาจส่งคืนสิ่งนี้:

table_name   |   table_row
-------------+----------------------------------------
public.foo   |  {"id": 1, "some_column": "foobar"}
public.bar   |  {"id": 42, "another_column": "barfoo"}

ตัวอย่างออนไลน์สำหรับ Postgres 10+

ตัวอย่างออนไลน์สำหรับ Postgres เวอร์ชันเก่า


ฉันพยายามเรียกใช้รหัสสำหรับ PostgreSQL เวอร์ชันเก่าและฉันได้รับข้อผิดพลาดต่อไปนี้ERROR: 42883: function format("unknown", information_schema.sql_identifier, information_schema.sql_identifier) does not exist
Matt

คุณอาจต้องแคสต์:format('%I.%I', table_schema::text, table_name::text)
a_horse_with_no_name

โอเคเสร็จแล้วตอนนี้ฉันมีERROR: 42883: function format("unknown", character varying, character varying) does not exist
แมตต์

จากนั้นรุ่น Postgres ของคุณหลายรุ่นก็เก่ามากแล้ว id นั้นไม่มีformat()ฟังก์ชัน
a_horse_with_no_name

ฉันคิดว่า Redshift ขึ้นอยู่กับ 8.3?
Matt

3

นี่คือฟังก์ชันของ @Daniel Véritéพร้อมฟังก์ชันการรายงานความคืบหน้า รายงานความคืบหน้าในสามวิธี:

  1. โดย RAISE NOTICE;
  2. โดยการลดค่าของลำดับ {progress_seq} ที่ให้มาจาก {จำนวนคอลัมน์ทั้งหมดที่จะค้นหาใน} ลงเป็น 0;
  3. โดยเขียนความคืบหน้าพร้อมกับตารางที่พบลงในไฟล์ข้อความซึ่งอยู่ใน c: \ windows \ temp \ {progress_seq} .txt

_

CREATE OR REPLACE FUNCTION search_columns(
    needle text,
    haystack_tables name[] default '{}',
    haystack_schema name[] default '{public}',
    progress_seq text default NULL
)
RETURNS table(schemaname text, tablename text, columnname text, rowctid text)
AS $$
DECLARE
currenttable text;
columnscount integer;
foundintables text[];
foundincolumns text[];
begin
currenttable='';
columnscount = (SELECT count(1)
      FROM information_schema.columns c
      JOIN information_schema.tables t ON
        (t.table_name=c.table_name AND t.table_schema=c.table_schema)
      WHERE (c.table_name=ANY(haystack_tables) OR haystack_tables='{}')
        AND c.table_schema=ANY(haystack_schema)
        AND t.table_type='BASE TABLE')::integer;
PERFORM setval(progress_seq::regclass, columnscount);

  FOR schemaname,tablename,columnname IN
      SELECT c.table_schema,c.table_name,c.column_name
      FROM information_schema.columns c
      JOIN information_schema.tables t ON
        (t.table_name=c.table_name AND t.table_schema=c.table_schema)
      WHERE (c.table_name=ANY(haystack_tables) OR haystack_tables='{}')
        AND c.table_schema=ANY(haystack_schema)
        AND t.table_type='BASE TABLE'
  LOOP
    EXECUTE format('SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L',
       schemaname,
       tablename,
       columnname,
       needle
    ) INTO rowctid;
    IF rowctid is not null THEN
      RETURN NEXT;
      foundintables = foundintables || tablename;
      foundincolumns = foundincolumns || columnname;
      RAISE NOTICE 'FOUND! %, %, %, %', schemaname,tablename,columnname, rowctid;
    END IF;
         IF (progress_seq IS NOT NULL) THEN 
        PERFORM nextval(progress_seq::regclass);
    END IF;
    IF(currenttable<>tablename) THEN  
    currenttable=tablename;
     IF (progress_seq IS NOT NULL) THEN 
        RAISE NOTICE 'Columns left to look in: %; looking in table: %', currval(progress_seq::regclass), tablename;
        EXECUTE 'COPY (SELECT unnest(string_to_array(''Current table (column ' || columnscount-currval(progress_seq::regclass) || ' of ' || columnscount || '): ' || tablename || '\n\nFound in tables/columns:\n' || COALESCE(
        (SELECT string_agg(c1 || '/' || c2, '\n') FROM (SELECT unnest(foundintables) AS c1,unnest(foundincolumns) AS c2) AS t1)
        , '') || ''',''\n''))) TO ''c:\WINDOWS\temp\' || progress_seq || '.txt''';
    END IF;
    END IF;
 END LOOP;
END;
$$ language plpgsql;

3

- ฟังก์ชันด้านล่างนี้จะแสดงรายการตารางทั้งหมดที่มีสตริงเฉพาะในฐานข้อมูล

 select TablesCount(‘StringToSearch’);

- ให้ความสำคัญกับตารางทั้งหมดในฐานข้อมูล

CREATE OR REPLACE FUNCTION **TablesCount**(_searchText TEXT)
RETURNS text AS 
$$ -- here start procedural part
   DECLARE _tname text;
   DECLARE cnt int;
   BEGIN
    FOR _tname IN SELECT table_name FROM information_schema.tables where table_schema='public' and table_type='BASE TABLE'  LOOP
         cnt= getMatchingCount(_tname,Columnames(_tname,_searchText));
                                RAISE NOTICE 'Count% ', CONCAT('  ',cnt,' Table name: ', _tname);
                END LOOP;
    RETURN _tname;
   END;
$$ -- here finish procedural part
LANGUAGE plpgsql; -- language specification

- ส่งคืนจำนวนตารางที่ตรงตามเงื่อนไข - ตัวอย่างเช่นหากข้อความที่ต้องการมีอยู่ในฟิลด์ใด ๆ ของตาราง - จำนวนจะมากกว่า 0 เราสามารถค้นหาการแจ้งเตือน - ในส่วนข้อความของโปรแกรมดูผลลัพธ์ในฐานข้อมูล postgres

CREATE OR REPLACE FUNCTION **getMatchingCount**(_tname TEXT, _clause TEXT)
RETURNS int AS 
$$
Declare outpt text;
    BEGIN
    EXECUTE 'Select Count(*) from '||_tname||' where '|| _clause
       INTO outpt;
       RETURN outpt;
    END;
$$ LANGUAGE plpgsql;

- รับฟิลด์ของแต่ละตาราง สร้างคำสั่ง where กับคอลัมน์ทั้งหมดของตาราง

CREATE OR REPLACE FUNCTION **Columnames**(_tname text,st text)
RETURNS text AS 
$$ -- here start procedural part
DECLARE
                _name text;
                _helper text;
   BEGIN
                FOR _name IN SELECT column_name FROM information_schema.Columns WHERE table_name =_tname LOOP
                                _name=CONCAT('CAST(',_name,' as VarChar)',' like ','''%',st,'%''', ' OR ');
                                _helper= CONCAT(_helper,_name,' ');
                END LOOP;
                RETURN CONCAT(_helper, ' 1=2');

   END;
$$ -- here finish procedural part
LANGUAGE plpgsql; -- language specification
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.