2011-03-18 15 views
55

एक समान प्रश्न here उपलब्ध है, लेकिन यह ओरेकल के लिए है। मेरे पास PostgreSQL के लिए एक ही सवाल है।सभी तालिकाओं में एक विशिष्ट मान कैसे खोजें (PostgreSQL)?

संक्षेप में, क्या PostgreSQL में किसी विशेष मान के लिए प्रत्येक तालिका के प्रत्येक फ़ील्ड को खोजना संभव है?

धन्यवाद।

+0

क्या आप किसी टूल की तलाश कर रहे हैं या लिंक किए गए प्रश्न में दिखाए गए प्रक्रियाओं के कार्यान्वयन के लिए? –

+0

नहीं, सभी फ़ील्ड/टेबल में विशिष्ट मान खोजने का सबसे आसान तरीका है। –

+0

तो आप बाहरी उपकरण का उपयोग नहीं करना चाहते हैं? –

उत्तर

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

+0

यदि आप टेक्स्ट डेटा को grep करना चाहते हैं (जो आम तौर पर पोस्टग्रेज़ के हाल के संस्करणों में एन्कोड किया गया है), तो आपको इसे डंप करने से पहले डेटाबेस (या इसकी प्रतिलिपि) पर अपने _db_name SET bytea_output = 'escape' को डेटा बदलने की आवश्यकता हो सकती है। (मुझे इसे सिर्फ 'pg_dump' कमांड के लिए निर्दिष्ट करने का कोई तरीका नहीं दिख रहा है।) – phils

+0

क्या आप विस्तार से समझा सकते हैं ..? सभी तालिकाओं में स्ट्रिंग 'एबीसी' कैसे खोजें? –

9

मैं जानता हूँ कि जो ऐसा कर सकते हैं केवल उपकरण है: एसक्यूएल Workbench/जम्मू: http://www.sql-workbench.net/

जो (या बस चयनित सभी के माध्यम से खोज करने के लिए एक विशेष (स्वामित्व) एसक्यूएल "कमांड" प्रदान करता है

एक जावा/JDBC आधारित उपकरण) एक डेटाबेस में तालिकाओं:

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

+0

क्या आप जानते हैं कि किसी विशिष्ट डेटा के बजाय किसी विशिष्ट कॉलम के नाम को खोजना संभव है? धन्यवाद। –

+0

उपकरण में सभी तालिकाओं के स्रोत कोड के माध्यम से खोजने के लिए एक और आदेश है: http://www.sql-workbench.net/manual/wb-commands.html#command-search-source –

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; 

संपादित : यह कोड पीजी 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) 
,

 
select * from public.w where ctid='(0,2)'; 
title | body |   tsv   
-------+--------+--------------------- 
toto | foobar | 'foobar':2 'toto':1 

फिर ग्रेप की तरह सख्त समानता के बजाय एक नियमित अभिव्यक्ति जांचने के लिए इस:

इसी आधार तालिका और और ctid साथ एक परिणाम पंक्ति जाओ

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

के लिए बदला जा सकता है:

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

त्रुटि: "डिफ़ॉल्ट" लाइन 3: haystack_tables पर या उसके आसपास वाक्यविन्यास त्रुटि का चयन करें नाम [] डिफ़ॉल्ट '{}' (PostgreSQL 8.2.17 का उपयोग करना और अपग्रेड नहीं कर सकता) – Henno

+0

@ हेनो: हाँ इसे पीजी-9.1 की आवश्यकता है। यह स्पष्ट करने के लिए अब संपादित किया गया। पुराने संस्करणों के साथ इसका उपयोग करने के लिए, आपको इसे अनुकूलित करना होगा। –

+0

दुर्भाग्य से मुझे अपने कौशल का अनुभव नहीं होता + समय उसके लिए पर्याप्त है ... मैंने postgresql फ़ंक्शन डिफ़ॉल्ट तर्क के लिए googling की कोशिश की लेकिन मुझे यह भी सुनिश्चित नहीं है कि समस्या नाम [] या डिफ़ॉल्ट कीवर्ड है या नहीं। – Henno

2

प्रगति रिपोर्टिंग कार्यक्षमता के साथ @ डैनियल वेरेट का कार्य यहां है। यह तीन तरीकों से प्रगति की रिपोर्ट करता है:

  1. RAISE नोटिस द्वारा;
  2. {0 से नीचे खोज करने के लिए कॉलम की कुल संख्या} से आपूर्ति {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

और अगर कोई लगता है कि यह मदद कर सकता है। यहां @ डैनियल वेरिएट का फ़ंक्शन है, एक और परम जो कॉलम के नाम स्वीकार करता है जिसका उपयोग खोज में किया जा सकता है। इस तरह यह प्रसंस्करण के समय को कम करता है। कम से कम मेरे परीक्षण में यह बहुत कम हो गया।

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

+1

मैंने स्ट्रिंग के लिए पैरामीटर नहीं बनाया है। आप या तो इसे हार्डकोड कर सकते हैं और इसे ब्लॉक के रूप में सख्ती से चला सकते हैं या इससे संग्रहीत प्रक्रिया बना सकते हैं। किसी भी मामले में, खोज के लिए आपकी स्ट्रिंग दो प्रतिशत संकेतों के बीच यहां जाती है: जहां अपर (', rec1। "Column_name",') जैसे अपर ('' ',' %% ',' '') – profimedica

संबंधित मुद्दे