2009-01-21 20 views
37

किसी डेटाबेस में SQL सर्वर में किसी तालिका में स्वतंत्र रूप से मौजूद है या नहीं, यह जांचने का सबसे अच्छा तरीका क्या है?जांचें कि कोई SQL तालिका मौजूद है

bool exists; 
    const string sqlStatement = @"SELECT COUNT(*) FROM my_table"; 

    try 
    { 
     using (OdbcCommand cmd = new OdbcCommand(sqlStatement, myOdbcConnection)) 
     { 
      cmd.ExecuteScalar(); 
      exists = true; 
     } 
    } 
    catch 
    { 
     exists = false; 
    } 

वहाँ यह करने के लिए एक बेहतर तरीका है:

मैं के साथ आया था? डेटाबेस से कनेक्शन विफल होने पर यह विधि काम नहीं करेगी। मुझे Sybase, SQL सर्वर, ओरेकल के लिए तरीके मिल गए हैं लेकिन कुछ भी नहीं जो सभी डेटाबेस के लिए काम करता है।

+1

एक बेहतर तरीका का उपयोग इस तरह से यह अभ्यस्त संसाधन लेने वाली के रूप में हो सकता है "' tbl' जहां 1 = 0 और 1 का चयन करने के लिए "होगा। –

उत्तर

56
bool exists; 

try 
{ 
    // ANSI SQL way. Works in PostgreSQL, MSSQL, MySQL. 
    var cmd = new OdbcCommand(
     "select case when exists((select * from information_schema.tables where table_name = '" + tableName + "')) then 1 else 0 end"); 

    exists = (int)cmd.ExecuteScalar() == 1; 
} 
catch 
{ 
    try 
    { 
     // Other RDBMS. Graceful degradation 
     exists = true; 
     var cmdOthers = new OdbcCommand("select 1 from " + tableName + " where 1 = 0"); 
     cmdOthers.ExecuteNonQuery(); 
    } 
    catch 
    { 
     exists = false; 
    } 
} 
+0

एसक्यूएल-सर्वर में info_schema पर अधिक जानकारी के लिए http://msdn.microsoft.com/en-us/library/ms186778.aspx इस लिंक को देखें। – GvS

+1

-1 मुझसे। यह MySQL में काम नहीं करता है। Coz, यह किसी भी डेटाबेस में 'tableName' नाम की एक तालिका है, तो यह सच हो जाता है। मैंने इसका परीक्षण MySQL 5.1 + Navicat8 के साथ किया है। – anonymous

+0

@JMSA: क्षमा करें, मैं schema_name (डेटाबेस नाम फ़ील्ड) शामिल करना भूल गया। 'select_schema.tables से चुनें * जहां schema_name = 'yourDatabaseNameHere' और table_name = 'yourTableNameHere'। कृपया डाउनवोट –

10

मुझे नहीं लगता कि एक सामान्य तरीका मौजूद है जो सभी डेटाबेस के लिए काम करता है, क्योंकि यह कुछ विशिष्ट है जो डीबी कैसे बनाया गया है इस पर निर्भर करता है।

लेकिन, आप एक विशिष्ट क्वेरी का उपयोग करके ऐसा क्यों करना चाहते हैं? क्या आप कार्यान्वयन को उस चीज़ से दूर नहीं कर सकते जो आप करना चाहते हैं? मेरा मतलब है: क्यों एक सामान्य इंटरफ़ेस नहीं बनाते, जो कि दूसरों के बीच है, उदाहरण के लिए 'TableExists (string tablename)' नामक एक विधि। फिर, प्रत्येक डीबीएमएस के लिए जिसे आप समर्थन देना चाहते हैं, आप एक कक्षा बनाते हैं जो इस इंटरफ़ेस को लागू करता है, और TableExists विधि में, आप इस डीबीएमएस के लिए विशिष्ट तर्क लिखते हैं।
SQLServer कार्यान्वयन में तब एक क्वेरी होगी जो sysobjects से पूछताछ करेगी।

आपके आवेदन में, आपके पास एक कारखाना वर्ग हो सकता है जो किसी दिए गए संदर्भ के लिए सही कार्यान्वयन बनाता है, और फिर आप टेबलएक्सिस्ट विधि को कॉल करते हैं।

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

IMyInterface foo = MyFactory.CreateMyInterface (SupportedDbms.SqlServer); 

if(foo.TableExists ("mytable")) 
... 

मुझे लगता है यह मैं इसे कैसे करना चाहिए है।

+1

इस तरह हम अपने मुख्य आवेदन में ऐसा करते हैं। हालांकि, अगर आपके पास अभी एक ओडीबीसी कनेक्शन है और यह नहीं पता कि इसके पीछे डेटाबेस क्या है? – Carra

+0

मेरा अनुभव बताता है कि यह एक गलत तरीका है! आपको संभवतः शून्य प्रदर्शन मिलेगा, दुर्भाग्य से – abatishchev

+0

@abtischev - क्या आप अधिक विस्तार से जा सकते हैं? – MPritchard

4

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

यदि आपको वास्तव में अपवाद अपने उदाहरण से निपटने का उपयोग कर जाँच करने के लिए है, तो आप निम्न क्वेरी एक COUNT (*) से अधिक कुशल है कि का उपयोग करना चाहिए क्योंकि डेटाबेस कोई वास्तविक चयन काम है करने के लिए:

SELECT 1 FROM my_table WHERE 1=2 
2

मेरे काम पर वर्तमान प्रोजेक्ट में मुझे 'डेटा एजेंट' लिखना होगा जो कई डेटाबेस प्रकारों का समर्थन करेगा।

तो मैं आगे क्या करने का फैसला किया: आभासी तरीकों का उपयोग कर (डेटाबेस स्वतंत्र) कार्यक्षमता आधार के साथ एक आधार वर्ग लिख सकते हैं और सभी डेटाबेस विशिष्ट क्षणों

उपवर्गों में ओवरराइड
+0

निश्चित रूप से ऐसा करने का तरीका, हां। – Nyerguds

4

मैं डीबीएमएस के रूप में select count(x) from xxxxxx को क्रियान्वित करने से बच जाएंगे वास्तव में होगा आगे बढ़ें और ऐसा करें जो बड़ी मेज के लिए कुछ समय ले सकता है।

इसके बजाय बस select * from mysterytable क्वेरी तैयार करें। अगर रहस्यमय अस्तित्व में नहीं है तो तैयार विफल हो जाएगा। वास्तव में तैयार कथन निष्पादित करने की कोई आवश्यकता नहीं है।

+0

मुझे ओडीबीसी के बारे में पता नहीं है, लेकिन ओडीकल पर जेडीबीसी का उपयोग करके आप एक बयान तैयार कर सकते हैं जो इसे चलाने पर पूरी तरह विफल हो जाएगा। –

+0

हां-- लेकिन वह केवल तभी दिखाना चाहता है जब तालिका मौजूद है जो तैयार करेगी।विशेष रूप से यदि यह आसान है "????? से चुनें * जो केवल तभी विफल हो सकता है ??? अस्तित्व में नहीं है। –

+0

मुझे सच में संदेह है कि "गिनती चुनें (*)" (जहां कहीं भी खंड नहीं है) एक बड़ी मेज के लिए लंबा समय लगेगा - मुझे लगता है कि सभी डेटाबेस आंतरिक डेटाबेस/इंडेक्स/कैश में पंक्ति गणना स्टोर करते हैं, इसलिए यह सिर्फ एक होगा एकल लुकअप इसलिए तालिका के आकार की क्वेरी के समय तक कोई प्रासंगिकता नहीं होगी। –

9

यदि आप डेटाबेस आजादी के लिए प्रयास कर रहे हैं तो आपको न्यूनतम मानक मानना ​​होगा।IIRC एएनएसआई INFORMATION_SCHEMA विचारों ODBC अनुरूपता के लिए आवश्यक हैं, तो आप उनके खिलाफ क्वेरी की तरह कर सकते हैं:

select count (*) 
    from information_schema.tables 
where table_name = 'foobar' 

यह देखते हुए कि आप ODBC उपयोग कर रहे हैं, आप भी विभिन्न ODBC API calls उपयोग कर सकते हैं और साथ ही इस मेटाडाटा को पुनः प्राप्त करने।

ध्यान रखें कि पोर्टेबिलिटी write-once test anywhere के बराबर में

भालू ताकि आप अभी भी आप का समर्थन करने का इरादा हर मंच पर आवेदन का परीक्षण करने के लिए जा रहे हैं। इसका मतलब यह है कि आप स्वाभाविक रूप से संभावित डेटाबेस प्लेटफॉर्म की सीमित संख्या तक ही सीमित हैं क्योंकि आपके पास परीक्षण के लिए केवल इतना संसाधन है।

उपरोक्त यह है कि आपको अपने एप्लिकेशन के लिए सबसे कम आम denominator खोजने की आवश्यकता है (जो कि एसक्यूएल की तुलना में काफी कठिन है) या एक मंच-निर्भर अनुभाग बनाएं जहां गैर पोर्टेबल कार्यों को प्लग इन किया जा सके एक प्रति मंच आधार।

+0

फिर, यदि मैं आपकी पोस्ट को सही ढंग से समझता हूं, तो प्रत्येक डीबीएमएस में कुछ मानक के अनुसार INFORMATION_SCHEMA दृश्य होना चाहिए? –

+0

मेरा मानना ​​है कि ANFORMATION_SCHEMA विचारों को एएनएसआई एसक्यूएल-9 2 मानक के अनुपालन के लिए आवश्यक है। हालांकि, डीबीएमएस विक्रेता अनुपालन के अपने दावों में एएनएसआई एसक्यूएल मानकों के साथ थोड़ा तेज़ और ढीला खेलते हैं। – ConcernedOfTunbridgeWells

1
मेरे लिए

अच्छी तरह से काम करता है निम्नलिखित ...

private bool TableExists(SqlConnection conn, string database, string name) 
{ 
    string strCmd = null; 
    SqlCommand sqlCmd = null; 

    try 
    { 
     strCmd = "select case when exists((select '['+SCHEMA_NAME(schema_id)+'].['+name+']' As name FROM [" + database + "].sys.tables WHERE name = '" + name + "')) then 1 else 0 end"; 
     sqlCmd = new SqlCommand(strCmd, conn); 

     return (int)sqlCmd.ExecuteScalar() == 1; 
    } 
    catch { return false; } 
} 
1

आप समाधान कोशिश पकड़ से बचने के लिए चाहते हैं, तो मैं इस विधि का सुझाव दे रहा हूँ, sys.tables

private bool IsTableExisting(string table) 
    { 
     string command = $"select * from sys.tables"; 
     using (SqlConnection con = new SqlConnection(Constr)) 
     using (SqlCommand com = new SqlCommand(command, con)) 
     { 
      SqlDataReader reader = com.ExecuteReader(); 
      while (reader.Read()) 
      { 
       if (reader.GetString(0).ToLower() == table.ToLower()) 
        return true; 
      } 
      reader.Close(); 
     } 
     return false; 
    } 
0

बहुत सरल का उपयोग करते हुए

use YOUR_DATABASE --OPTIONAL 
SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name = 'YOUR_TABLE_NAME' 

यदि उत्तर 1 है, तो एक तालिका है। यदि उत्तर 0 है, तो कोई तालिका नहीं है।

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