2013-03-26 17 views
5

मैं रिपोर्टिंग के लिए एक जटिल दृश्य के परिणामों को डंप करने के लिए एक साधारण स्क्रिप्ट बनाने की कोशिश कर रहा हूं। मैंने व्यू और टेबल नामों को ट्वीक करने के लिए समानार्थी शब्द का उपयोग किया है।मैं कैसे जांच सकता हूं कि समानार्थी के पीछे तालिका मौजूद है

विचार यह है कि स्क्रिप्ट का उपयोगकर्ता उस स्रोत का नाम डाल सकता है जिसे वे स्रोत के रूप में उपयोग करना चाहते हैं, और शुरुआत में और दूर लक्ष्य रिपोर्टिंग तालिका का नाम वे जाते हैं। यदि तालिका मौजूद नहीं है तो स्क्रिप्ट इसे बनाना चाहिए। यदि तालिका पहले से मौजूद है तो स्क्रिप्ट को केवल उस दृश्य से रिकॉर्ड्स की प्रतिलिपि बनाना चाहिए जो पहले से ही तालिका में नहीं है।

स्क्रिप्ट नीचे उन सभी आवश्यकताओं को शामिल किया गया है, लेकिन मैं अगर पर्याय पीछे तालिका पहले से मौजूद है की जाँच करने के लिए एक अच्छी तरह से नहीं मिल सकता है:

CREATE SYNONYM SourceView FOR my_view 
CREATE SYNONYM TargetReportingTable FOR my_table 

-- Here's where I'm having trouble, how do I check if the underlying table exists? 
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = TargetReportingTable) = 0 
    BEGIN 
    -- Table does not exists, so insert into. 
    SELECT * INTO TargetReportingTable FROM SourceView 
    END 
ELSE 
    BEGIN 
    -- Table already exists so work out the last record which was copied over 
    -- and insert only the newer records. 
    DECLARE @LastReportedRecordId INT; 
    SET @LastReportedRecordId = (SELECT MAX(RecordId) FROM TargetReportingTable) 
    INSERT INTO TargetReportingTable SELECT * FROM SourceView WHERE RecordId > @LastReportedRecordId 
    END 

DROP SYNONYM SourceView 
DROP SYNONYM TargetReportingTable 

मैं जानता हूँ कि मैं सिर्फ स्क्रिप्ट के उपयोगकर्ता मिल सकता है तालिका नाम को 'info_schema' लाइन में और शीर्ष पर समानार्थी में कॉपी करने के लिए, लेकिन यह त्रुटि के लिए दायरा छोड़ देता है।

मुझे यह भी पता है कि मैं कुछ गड़बड़ कर सकता हूं जैसे तालिका का नाम एक चर में डालता है और एसक्यूएल को स्ट्रिंग के रूप में बाहर निकाल देता है, लेकिन इससे मुझे थोड़ा बीमार महसूस होता है!

क्या मेरे लिए यह देखने के लिए एक अच्छा सुरुचिपूर्ण एसक्यूएल तरीका है कि समानार्थी के पीछे की तालिका मौजूद है या नहीं? या समस्या को हल करने का एक बिल्कुल अलग तरीका है?

+2

कृपया विशिष्ट RDBMS के साथ अपने प्रश्न को टैग, बस नहीं "एसक्यूएल" – Barmar

+1

क्षमा करें, रूकी त्रुटि में मौजूद है आप परीक्षण कर सकते हैं। संपादन के लिए धन्यवाद। – Tom

+0

क्या हम डेटाबेस में समानार्थी बिंदु मान सकते हैं जो समानार्थी है, या किसी अन्य डीबी को इंगित कर सकता है? –

उत्तर

3

समाधानों का सबसे सुंदर नहीं है, लेकिन आप sys.synonyms तालिका में sys.tables तालिका में शामिल हो सकते हैं यह जांचने के लिए कि तालिका मौजूद है या नहीं।

यदि तालिका मौजूद नहीं है, तो शामिल हो जाएगा विफल हो जाएगा और आपको 0 पंक्तियां मिलेंगी (इसलिए IF EXISTS गलत होगी)। तालिका मौजूद है, तो इच्छा सफलता में शामिल होने और आप 1 पंक्ति (और सही) मिल जाएगा:

IF EXISTS( SELECT * 
       FROM sys.synonyms s 
       INNER JOIN sys.tables t ON REPLACE(REPLACE(s.base_object_name, '[', ''), ']', '') = t.name 
       WHERE s.name = 'TargetReportingTable') 
BEGIN 
    -- Does exist 
END 
ELSE 
BEGIN 
    -- Does not exist 
END 

बदलें 'TargetReportingTable' साथ जो भी पर्याय आप जांचना चाहते हैं।

+0

धन्यवाद जो अच्छी तरह से काम करता है। यद्यपि आप कहते हैं कि यह सबसे सुंदर सवाल नहीं है, कम से कम इसका मतलब है कि स्क्रिप्ट के उपयोगकर्ता को टेबल नाम को कई स्थानों पर पेस्ट करने की आवश्यकता नहीं है। – Tom

+1

'REPLACE' का उपयोग करने के बजाय, तालिका और स्कीमा जानकारी प्राप्त करने का एक और अधिक विश्वसनीय तरीका' PARSENAME' फ़ंक्शन का उपयोग करना होगा। देखें: https://msdn.microsoft.com/en-us/library/ms188006.aspx – Nathan

1

आप गतिशील एसक्यूएल के साथ ऐसा कर सकते हैं:

-- create synonym a for information_schema.tables 
create synonym a for b 

declare @exists int = 1; 
begin try 
    exec('select top 0 * from a'); 
end try 
begin catch 
    set @exists = 0; 
end catch 
select @exists; 

क्योंकि पर्याय संदर्भ संकलन समय पर पकड़ा है यह, गैर गतिशील एसक्यूएल के साथ काम नहीं करता। इसका मतलब है कि कोड सिर्फ एक संदेश के साथ विफल रहता है और try/catch ब्लॉक द्वारा पकड़ा नहीं जाता है। गतिशील एसक्यूएल के साथ, ब्लॉक त्रुटि पकड़ता है।

+0

धन्यवाद। मैं काफी नहीं देख रहा हूं कि यह कैसे मदद करता है। यह info_schema तालिका नहीं है जिसे मैं नाम प्राप्त करने का प्रयास कर रहा हूं, यह समानार्थी के पीछे असली तालिका है (जिसे उपरोक्त मेरी स्क्रिप्ट में 'TargetReportingTable' कहा जाता है)। क्या मुझे कुछ याद आया है? – Tom

+0

@ टॉम। । । यह दिखाने के लिए उदाहरण हैं कि कोड काम करता है। डेटाबेस में मैं परीक्षण कर रहा हूं, 'बी' मौजूद नहीं है, इसलिए इसे '@'' को मौजूद है। जब मौजूद तालिका में सेट किया जाता है, तो '1' असाइन किया जाता है। –

2

उपरोक्त समाधान मेरे लिए काम नहीं करते हैं यदि समानार्थी ने किसी अन्य डेटाबेस का संदर्भ दिया हो। मैं हाल ही में समारोह [fn_my_permissions] जो एक विशिष्ट डेटाबेस वस्तु के लिए अनुमतियों को दिखाने के लिए उपयोगी है की खोज की है, इसलिए मैं इस इस प्रकार किया जा सकता है समझ:

IF EXISTS 
(
select * 
from sys.synonyms sy 
cross apply fn_my_permissions(sy.base_object_name, 'OBJECT') 
WHERE sy.name = 'TargetReportingTable' 
) 
print 'yes - I exist!' 
+0

मुझे ओरेकल के मेरे संस्करण में "sy.sname" का उपयोग करना पड़ा। इसके अलावा मुझे अपने उद्देश्यों के लिए आवश्यक क्रॉस लागू नहीं मिला – Mangusta

1

पार्टी के लिए देर हो चुकी है, मैं बाहर का परीक्षण करने के एक प्रश्न बना लिया है Synonyms का अस्तित्व और आपके साथ साझा करें।

DECLARE @Synonyms table 
(
    ID int identity(1,1), 
    SynonymsDatabaseName sysname, 
    SynonymsSchemaName sysname, 
    SynonymsName sysname, 
    DatabaseName nvarchar(128), 
    SchemaName nvarchar(128), 
    ObjectName nvarchar(128), 

    Remark nvarchar(max), 
    IsExists bit default(0) 
) 

INSERT @Synonyms (SynonymsDatabaseName, SynonymsSchemaName, SynonymsName, DatabaseName, SchemaName, ObjectName) 
SELECT 
    DB_NAME() AS SynonymsDatabaseName, 
    SCHEMA_NAME(schema_id) AS SynonymsSchemaName, 
    name AS SynonymsName, 
    PARSENAME(base_object_name,3) AS DatabaseName, 
    PARSENAME(base_object_name,2) AS SchemaName, 
    PARSENAME(base_object_name,1) AS ObjectName 
FROM sys.synonyms 


SET NOCOUNT ON 

DECLARE @ID int = 1, @Query nvarchar(max), @Remark nvarchar(max) 

WHILE EXISTS(SELECT * FROM @Synonyms WHERE ID = @ID) 
BEGIN 

    SELECT 
     @Query = 'SELECT @Remark = o.type_desc FROM [' + DatabaseName + '].sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE s.name = ''' + SchemaName + ''' AND o.name = ''' + ObjectName + '''' 
    FROM @Synonyms WHERE ID = @ID 

    EXEC sp_executesql @Query, N'@Remark nvarchar(max) OUTPUT', @Remark OUTPUT; 

    UPDATE @Synonyms SET IsExists = CASE WHEN @Remark IS NULL THEN 0 ELSE 1 END, Remark = @Remark WHERE ID = @ID 

    SELECT @ID += 1, @Remark = NULL 
END 

SELECT * FROM @Synonyms 
0

अगर पर्याय अपने डेटाबेस SQL ​​सर्वर में object_id समारोह उपलब्ध का उपयोग कर

IF OBJECT_ID('YourDatabaseName..YourSynonymName') IS NOT NULL 
    PRINT 'Exist SYNONYM' 
ELSE 
    PRINT 'Not Exist SYNONYM' 
संबंधित मुद्दे