2011-03-18 136 views
55

有類似的問題here,但它適用於Oracle。我對PostgreSQL有同樣的問題。如何搜索所有表(PostgreSQL)中的特定值?

簡而言之,是否有可能在PostgreSQL中搜索每個表的每個字段以獲取特定值?

謝謝。

+0

您是否正在尋找工具或鏈接問題中顯示的過程的實現? – 2011-03-18 09:49:11

+0

不,只是在所有字段/表格中查找特定值的最簡單方法。 – 2011-03-18 09:51:29

+0

所以你不想使用外部工具? – 2011-03-18 09:56:52

回答

79

如何轉儲數據庫中的內容,然後使用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'); 
+3

+1免費且簡單。如果你想要結構pg_dump也可以。此外,如果grep不是你的東西,你可以使用你想要的文件內容搜索工具在被甩出的結構和/或數據上。 – Kuberchaun 2011-03-18 12:17:12

+0

如果您想要grep文本數據(通常使用最新版本的postgres編碼),您可能需要在轉儲數據庫(或其副本)之前對您的數據庫進行ALTER DATABASE SET bytea_output ='escape';'。 (我沒有看到一個方法來指定這只是一個'pg_dump'命令。) – phils 2015-08-10 03:01:10

+0

你能詳細解釋..?如何在所有表中搜索字符串'ABC'? – 2017-01-28 06:47:57

9

我知道它可以做到這一點的唯一工具是:SQL工作臺/ J:http://www.sql-workbench.net/

一個Java/JDBC基礎工具,它提供了一個特殊(專有)SQL「命令」,通過全搜索(或只是選擇)數據庫中的表:

http://www.sql-workbench.net/manual/wb-commands.html#command-search-data
http://www.sql-workbench.net/wbgrepdata_png.html

+0

你知道是否可以搜索特定列的名稱而不是特定的數據?謝謝。 – 2011-03-18 10:18:58

+0

該工具有另一個命令來搜索所有表的源代碼:http://www.sql-workbench.net/manual/wb-commands.html#command-search-source – 2011-03-18 10:37:10

36

這是一個pl/pgsql函數,用於查找任何列包含特定值的記錄。 它以文本格式搜索的值作爲參數,要搜索的表名稱數組(缺省爲所有表)和模式名稱數組(缺省爲所有模式名稱)。

它返回模式,表的名稱,名稱欄和僞列ctid的表結構(表中的行的非持久的物理位置,見System Columns

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) 
     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 
    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; 

EDIT :此代碼適用於PG 9.1或更新版本。在測試數據庫使用的

例子:

公共架構中的所有表中搜索:

 
select * from search_columns('foobar'); 
schemaname | tablename | columnname | rowctid 
------------+-----------+------------+--------- 
public  | s3  | usename | (0,11) 
public  | s2  | relname | (7,29) 
public  | w   | body  | (0,2) 
(3 rows) 

搜索特定表:

 
select * from search_columns('foobar','{w}'); 
schemaname | tablename | columnname | rowctid 
------------+-----------+------------+--------- 
public  | w   | body  | (0,2) 
(1 row) 

表中的一個子集搜索從一個選擇中獲得:

 
select * from search_columns('foobar', array(select table_name::name from information_schema.tables where table_name like 's%'), array['public']); 
schemaname | tablename | columnname | rowctid 
------------+-----------+------------+--------- 
public  | s2  | relname | (7,29) 
public  | s3  | usename | (0,11) 
(2 rows) 

得到一個結果行與相應的基臺和和CTID:

 
select * from public.w where ctid='(0,2)'; 
title | body |   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 
+0

錯誤:語法錯誤處於或默認爲「default」 LINE 3:haystack_tables name []默認'{}'(使用PostgreSQL 8.2.17,不能升級) – Henno 2014-05-11 08:54:39

+0

@Henno:是的,它需要PG-9.1。現在編輯,以明確。要在舊版本中使用它,您必須修改它。 – 2014-05-11 12:27:07

+0

不幸的是,我不覺得我的技能+時間就足夠了......我試着用google搜索postgresql函數的默認參數,但我甚至不確定問題是名稱[]還是默認關鍵字。 – Henno 2014-05-11 17:32:33

2

這裏是@DanielVé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; 
4

如果有人認爲這可能會有幫助。這裏是@DanielVé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; 

波紋管是上面創建的search_function的使用示例。

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') 
); 
2

不存儲新過程,您可以使用代碼塊並執行以獲取出現的表。您可以按架構,表或列名稱篩選結果。

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; 
+0

你在哪裏指定搜索字符串?或者,這只是傾銷整個數據庫,一桌一桌? – jimtut 2017-08-16 17:24:30

+1

我沒有爲字符串創建參數。您可以對其進行硬編碼並直接作爲塊運行,或者從中創建存儲過程。無論如何,你要搜索的字符串在兩個百分號之間:WHERE UPPER(',rec1。「column_name」,')LIKE UPPER(''','%%',''') – profimedica 2017-08-16 22:13:25

相關問題