यदि किसी दिए गए स्कीमा में तालिका मौजूद है, तो कैसे जांचें


149

8.4 और अधिक से अधिक डेटाबेस में publicस्कीमा में सामान्य तालिकाएँ और स्कीमा में कंपनी की विशिष्ट तालिकाएँ होती हैं company
companyस्कीमा नाम हमेशा 'company'कंपनी नंबर के साथ शुरू और समाप्त होते हैं।
तो वहाँ स्कीमा हो सकता है जैसे:

public
company1
company2
company3
...
companynn

एक आवेदन हमेशा एक ही कंपनी के साथ काम करता है। ODBC या npgsql कनेक्शन स्ट्रिंग की तरह, में तदनुसार निर्दिष्ट किया जाता है:
search_path

search_path='company3,public'

यदि किसी निर्दिष्ट companynस्कीमा में दी गई तालिका मौजूद है, तो आप कैसे जाँचेंगे?

उदाहरण के लिए:

select isSpecific('company3','tablenotincompany3schema')

लौटना चाहिए false, और

select isSpecific('company3','tableincompany3schema')

लौट जाना चाहिए true

किसी भी स्थिति में, फ़ंक्शन को केवल companynस्कीमा पास की जांच करनी चाहिए , अन्य स्कीमाओं की नहीं।

यदि एक दी गई तालिका दोनों publicऔर पास स्कीमा में मौजूद है , तो फ़ंक्शन को वापस लौटना चाहिए true
यह Postgres 8.4 या बाद के लिए काम करना चाहिए।

जवाबों:


284

यह इस बात पर निर्भर करता है कि आप वास्तव में क्या परीक्षण करना चाहते हैं

सूचना स्कीमा?

यह पता लगाने के लिए कि "तालिका मौजूद है" ( कोई फर्क नहीं पड़ता कि कौन पूछ रहा है ), सूचना स्कीमा ( information_schema.tables) को गलत बताते हुए, सख्ती से बोल रहा है, क्योंकि ( प्रति प्रलेखन ):

केवल उन तालिकाओं और विचारों को दिखाया गया है कि वर्तमान उपयोगकर्ता की पहुंच है (स्वामी होने के नाते या कुछ विशेषाधिकार होने के कारण)।

@Kong द्वारा प्रदान की गई क्वेरी वापस आ सकती है FALSE, लेकिन तालिका अभी भी मौजूद हो सकती है। यह सवाल का जवाब देता है:

यह कैसे जांचें कि क्या एक तालिका (या दृश्य) मौजूद है, और वर्तमान उपयोगकर्ता की पहुंच है?

SELECT EXISTS (
   SELECT FROM information_schema.tables 
   WHERE  table_schema = 'schema_name'
   AND    table_name   = 'table_name'
   );

सूचना स्कीमा मुख्य रूप से प्रमुख संस्करणों में और विभिन्न आरडीबीएमएस के पार पोर्टेबल रहने के लिए उपयोगी है। लेकिन कार्यान्वयन धीमा है, क्योंकि पोस्टग्रेज को मानक का पालन करने के लिए परिष्कृत विचारों का उपयोग करना पड़ता है ( information_schema.tablesयह एक सरल उदाहरण है)। और कुछ जानकारी (जैसे ओआईडी) सिस्टम कैटलॉग से अनुवाद में खो जाती है - जो वास्तव में सभी जानकारी ले जाती है।

सिस्टम कैटलॉग

आपका प्रश्न था:

कैसे जांचें कि क्या कोई तालिका मौजूद है?

SELECT EXISTS (
   SELECT FROM pg_catalog.pg_class c
   JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
   WHERE  n.nspname = 'schema_name'
   AND    c.relname = 'table_name'
   AND    c.relkind = 'r'    -- only tables
   );

सिस्टम कैटलॉग का उपयोग करें pg_classऔर pg_namespaceसीधे, जो भी काफी तेज है। हालाँकि, प्रति प्रलेखनpg_class :

सूची pg_classकैटलॉग टेबल और बाकी सबसे सब कुछ है कि स्तंभ होते हैं या नहीं तो एक मेज के समान है। इसमें अनुक्रमित (लेकिन यह भी देखें pg_index), अनुक्रम , विचार , भौतिक विचार , समग्र प्रकार और टोस्ट टेबल शामिल हैं ;

इस विशेष प्रश्न के लिए आप सिस्टम दृश्य काpg_tables उपयोग कर सकते हैं । प्रमुख पोस्टग्रेज संस्करणों में थोड़ा सरल और अधिक पोर्टेबल (जो इस मूल प्रश्न के लिए चिंता का विषय नहीं है):

SELECT EXISTS (
   SELECT FROM pg_tables
   WHERE  schemaname = 'schema_name'
   AND    tablename  = 'table_name'
   );

ऊपर उल्लिखित सभी वस्तुओं के बीच पहचानकर्ता अद्वितीय होना चाहिए । यदि आप पूछना चाहते हैं:

यह कैसे जांचें कि किसी दिए गए स्कीमा में तालिका या इसी तरह की वस्तु का नाम लिया गया है?

SELECT EXISTS (
   SELECT FROM pg_catalog.pg_class c
   JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
   WHERE  n.nspname = 'schema_name'
   AND    c.relname = 'table_name'
   );

वैकल्पिक: कास्ट करने के लिए regclass

SELECT 'schema_name.table_name'::regclass

यह एक अपवाद उठाता है यदि वैकल्पिक रूप से स्कीमा-योग्य) तालिका (या उस नाम पर कब्जा करने वाली अन्य वस्तु) मौजूद नहीं है।

यदि आप तालिका के नाम को स्कीमा-अर्हता प्राप्त नहीं करते हैं, तो पहली तालिका के लिए OID को regclassचूक करने search_pathऔर वापस करने के लिए एक कास्ट मिला है - या एक अपवाद यदि तालिका सूचीबद्ध स्कीमा में से कोई भी नहीं है। ध्यान दें कि सिस्टम स्कीमाpg_catalog और pg_temp(वर्तमान सत्र की अस्थायी वस्तुओं के लिए स्कीमा) स्वचालित रूप से इसका हिस्सा हैं search_path

आप इसका उपयोग कर सकते हैं और एक फ़ंक्शन में एक संभावित अपवाद को पकड़ सकते हैं। उदाहरण:

ऊपर की तरह एक क्वेरी संभव अपवाद से बचा जाता है और इसलिए थोड़ा तेज है।

to_regclass(rel_name) पोस्टग्रैज में 9.4+

बहुत सरल अब:

SELECT to_regclass('schema_name.table_name');

कलाकारों के रूप में भी, लेकिन यह रिटर्न ...

... यदि नाम नहीं मिला है, तो एक त्रुटि को फेंकने के बजाय अशक्त करें


4
शेल से:[[ `psql dbname -tAc "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'ejabberd' AND table_name = 'users');"` = 't' ]]
ब्रालिओबो

1
क्या कोई कारण है कि आप pg_tables का उपयोग नहीं कर रहे हैं ?
m0meni

1
pg_tablesवास्तव में "कैसे एक टेबल मौजूद है की जाँच करने के लिए एक अच्छा विचार है?" (के लिए जांच की जा रही तालिकाओं केवल ।, नहीं अन्य प्रयोजनों के लिए, जैसे कि ऊपर बताया गया इसके अलावा, pg_tablesकई तालिकाओं को शामिल एक दृश्य है ( pg_class, pg_namespace, pg_tablespace), थोड़ा अधिक महंगा है जो सबसे महत्वपूर्ण कारण:। मैं क्वेरी करने के लिए इस्तेमाल कर रहा हूँ pg_classसीधे और नहीं था pg_tablesइस उत्तर को लिखते समय सोचें । मैंने इसे अब ऊपर जोड़ा, धन्यवाद।
इरविन ब्रांडस्टेटर

1
@ sage88: सही है, मैंने अपनी गलत टिप्पणी को हटा दिया। pg_my_temp_schema()यदि यह मौजूद है तो आप वास्तविक अस्थायी स्कीमा का ओआईडी प्राप्त करने के लिए उपयोग कर सकते हैं । (लेकिन विचारों में information_schemaशामिल नहीं हैं ओआईडी। आप कर सकते हैं SELECT nspname FROM pg_namespace WHERE OID = pg_my_temp_schema()) आपके परीक्षण में कई कमजोरियां हैं। एक सही परीक्षण table_schema LIKE 'pg\_temp\_%'या सख्त होगा table_schema ~ '^pg_temp_\d+$':।
एरविन ब्रान्डसेट्टर

1
@PeterKrauss यदि आपको 9.4 वर्ष से अधिक पुराने पोस्टग्रेजुएट संस्करण पर the_regclass फ़ंक्शन का उपयोग करने का प्रयास करने पर वह त्रुटि मिलेगी।
spetz83

44

शायद info_schema का उपयोग करें :

SELECT EXISTS(
    SELECT * 
    FROM information_schema.tables 
    WHERE 
      table_schema = 'company3' AND 
      table_name = 'tableincompany3schema'
);

0

PostgreSQL 9.3 या उससे कम के लिए ... या जो पाठ को सभी सामान्यीकृत पसंद करता है

मेरे पुराने SwissKnife पुस्तकालय के तीन जायके: relname_exists(anyThing), relname_normalized(anyThing)और relnamechecked_to_array(anyThing)Pg_catalog.pg_class तालिका से सभी चेक , और मानक सार्वभौमिक डेटाटेस ( बूलियन , पाठ या पाठ []) लौटाता है ।

/**
 * From my old SwissKnife Lib to your SwissKnife. License CC0.
 * Check and normalize to array the free-parameter relation-name.
 * Options: (name); (name,schema), ("schema.name"). Ignores schema2 in ("schema.name",schema2).
 */
CREATE FUNCTION relname_to_array(text,text default NULL) RETURNS text[] AS $f$
     SELECT array[n.nspname::text, c.relname::text]
     FROM   pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace,
            regexp_split_to_array($1,'\.') t(x) -- not work with quoted names
     WHERE  CASE
              WHEN COALESCE(x[2],'')>'' THEN n.nspname = x[1]      AND c.relname = x[2]
              WHEN $2 IS NULL THEN           n.nspname = 'public'  AND c.relname = $1
              ELSE                           n.nspname = $2        AND c.relname = $1
            END
$f$ language SQL IMMUTABLE;

CREATE FUNCTION relname_exists(text,text default NULL) RETURNS boolean AS $wrap$
  SELECT EXISTS (SELECT relname_to_array($1,$2))
$wrap$ language SQL IMMUTABLE;

CREATE FUNCTION relname_normalized(text,text default NULL,boolean DEFAULT true) RETURNS text AS $wrap$
  SELECT COALESCE(array_to_string(relname_to_array($1,$2), '.'), CASE WHEN $3 THEN '' ELSE NULL END)
$wrap$ language SQL IMMUTABLE;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.