क्या TSQL में स्क्रिप्ट बनाने के लिए एक तरीका है?


22

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

अब मुझे उस स्थिति का वर्णन करना चाहिए जिसका मैं सामना कर रहा हूं, क्योंकि इससे संपर्क करने का एक अलग तरीका हो सकता है। मेरे पास कई दर्जन डेटाबेस के साथ एक उदाहरण है। इन डेटाबेस में सभी एक ही स्कीमा, सभी समान टेबल, इंडेक्स और इतने पर हैं। उन्हें तीसरे पक्ष के सॉफ़्टवेयर इंस्टॉलेशन के एक भाग के रूप में बनाया गया था। मुझे उनके साथ काम करने का एक तरीका होना चाहिए ताकि मैं उनसे तदर्थ तरीके से डेटा एकत्र कर सकूं। Dba.se में अच्छे लोग पहले ही मेरी मदद कर चुके हैं कि एक अलग डेटाबेस में ट्रिगर कैसे बनाएं?

वर्तमान में मुझे सभी डेटाबेस में एक तालिका से चयन करने का एक तरीका खोजने की आवश्यकता है। मैंने सभी डेटाबेस नामों को एक तालिका में दर्ज किया है Databaseesऔर मैंने निम्नलिखित स्क्रिप्ट को उन सभी पर एक चयन कथन को निष्पादित करने के लिए लिखा है:

IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp

select * into #tmp from Database1.dbo.Table1 where 1=0
DECLARE @statement nvarchar(max) = 
  N'insert into #tmp select * from Table1 where Column1=0 and Cloumn2 =1'

DECLARE @LastDatabaseID INT
SET @LastDatabaseID = 0

DECLARE @DatabaseNameToHandle varchar(60)
DECLARE @DatabaseIDToHandle int

SELECT TOP 1 @DatabaseNameToHandle = Name,
@DatabaseIDToHandle = Database_Ref_No
FROM Databasees
WHERE Database_Ref_No > @LastDatabaseID
ORDER BY Database_Ref_No

WHILE @DatabaseIDToHandle IS NOT NULL
BEGIN

  DECLARE @sql NVARCHAR(MAX) = QUOTENAME(@DatabaseNameToHandle) + '.dbo.sp_executesql'
  EXEC @sql @statement

  SET @LastDatabaseID = @DatabaseIDToHandle
  SET @DatabaseIDToHandle = NULL

  SELECT TOP 1 @DatabaseNameToHandle = Name,
  @DatabaseIDToHandle = Database_Ref_No
  FROM Databasees
  WHERE Database_Ref_No > @LastDatabaseID
  ORDER BY Database_Ref_No
END

select * from #tmp
DROP TABLE #tmp

हालाँकि उपरोक्त स्क्रिप्ट निम्न संदेश के साथ विफल है:

तालिका '#tmp' में पहचान कॉलम के लिए एक स्पष्ट मूल्य केवल तब निर्दिष्ट किया जा सकता है जब एक कॉलम सूची का उपयोग किया जाता है और IDENTITY_INSERT चालू होता है।

इसे जोड़ना:

SET IDENTITY_INSERT #tmp ON

मदद नहीं करता है, क्योंकि, मैं कॉलम सूची निर्दिष्ट नहीं कर सकता और इसे सामान्य रख सकता हूं।

SQL में किसी दिए गए टेबल पर पहचान को स्विच करने का कोई तरीका नहीं है। आप केवल एक कॉलम ड्रॉप कर सकते हैं और एक कॉलम जोड़ सकते हैं, जो स्पष्ट रूप से कॉलम ऑर्डर को बदल देता है। और यदि स्तंभ क्रम बदलता है, तो आपको, फिर से, कॉलम सूची को निर्दिष्ट करने की आवश्यकता है, जो आपके द्वारा क्वेरी की गई तालिका के आधार पर भिन्न होगी।

तो मैं सोच रहा था कि क्या मैं अपने टी-एसक्यूएल कोड में टेबल टेबल क्रिएट कर सकता हूं, मैं पहचान कॉलम को हटाने के लिए स्ट्रिंग हेरफेर अभिव्यक्तियों के साथ हेरफेर कर सकता हूं और परिणाम के सेट के लिए डेटाबेस के नाम के लिए एक कॉलम भी जोड़ सकता हूं ।

क्या कोई भी मुझे प्राप्त करने के लिए अपेक्षाकृत आसान तरीका सोच सकता है?

जवाबों:


28

2007 में वापस, मैंने CREATE TABLEयूआई या एसएमओ का उपयोग करने के बजाय टी-एसक्यूएल के माध्यम से एक स्क्रिप्ट उत्पन्न करने का एक आसान तरीका पूछा । मुझे संक्षेप में खारिज कर दिया गया था

हालाँकि, SQL Server 2012 यह बहुत आसान बनाता है। आइए दिखाते हैं कि हमारे पास एक ही स्कीमा है जिसमें कई डेटाबेस हैं, जैसे dbo.whatcha:

CREATE TABLE dbo.whatcha
(
  id INT IDENTITY(1,1), 
  x VARCHAR(MAX), 
  b DECIMAL(10,2), 
  y SYSNAME
);

निम्न स्क्रिप्ट नए sys.dm_exec_describe_first_results_setडायनेमिक प्रबंधन फ़ंक्शन का उपयोग करके प्रत्येक कॉलम के लिए उचित डेटा प्रकार (और IDENTITYसंपत्ति की अनदेखी ) प्राप्त करने के लिए उपयोग करता है । यह आपकी ज़रूरत की #tmp तालिका बनाता है, आपकी सूची के प्रत्येक डेटाबेस से आवेषण, और फिर #tmp से, सभी एक ही गतिशील SQL बैच के भीतर और एक WHILEलूप का उपयोग किए बिना चयन करता है (जो इसे बेहतर नहीं बनाता है, बस सरल है देखो और आप Database_Ref_Noपूरी तरह से उपेक्षा करने की अनुमति देता है :-))।

SET NOCOUNT ON;

DECLARE @sql NVARCHAR(MAX), @cols NVARCHAR(MAX) = N'';

SELECT @cols += N',' + name + ' ' + system_type_name
  FROM sys.dm_exec_describe_first_result_set(N'SELECT * FROM dbo.whatcha', NULL, 1);

SET @cols = STUFF(@cols, 1, 1, N'');

SET @sql = N'CREATE TABLE #tmp(' + @cols + ');'

DECLARE @dbs TABLE(db SYSNAME);

INSERT @dbs VALUES(N'db1'),(N'db2');
  -- SELECT whatever FROM dbo.databases

SELECT @sql += N'
  INSERT #tmp SELECT ' + @cols + ' FROM ' + QUOTENAME(db) + '.dbo.tablename;'
  FROM @dbs;

SET @sql += N'
  SELECT ' + @cols + ' FROM #tmp;';

PRINT @sql;
-- EXEC sp_executesql @sql;

परिणामी PRINTआउटपुट:

CREATE TABLE #tmp(id int,x varchar(max),b decimal(10,2),y nvarchar(128));
  INSERT #tmp SELECT id,x,b,y FROM [db1].dbo.tablename;
  INSERT #tmp SELECT id,x,b,y FROM [db2].dbo.tablename;
  SELECT id,x,b,y FROM #tmp;

जब आप आश्वस्त होते हैं कि यह वही कर रहा है जो आप उम्मीद करते हैं, तो बस असहज करें EXEC

(यह आप पर भरोसा करता है कि स्कीमा एक ही है; यह इस बात को मान्य नहीं करता है कि एक या एक से अधिक टेबल बदल दिए गए हैं, और परिणामस्वरूप हो सकता है।)


वह पहचान चश्मा क्यों नहीं बनाता है?
FindOutIslamNow

1
@Kilanny क्या आपने पूरे उत्तर को पढ़ा है, जैसे कि मैं उस हिस्से के बारे में बात करता हूं जहां हम पहचान संपत्ति की अनदेखी कर रहे हैं?
हारून बर्ट्रेंड

मुझे पूर्ण तालिका परिभाषा (पहचान, अनुक्रमित, बाधा सहित ..) की आवश्यकता है। शुक्र है मैंने पाया इस महान स्क्रिप्ट stormrage.com/SQLStuff/sp_GetDDLa_Latest.txt वैसे भी धन्यवाद
FindOutIslamNow

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

हारून, यह एक चुटकी में एक सुरुचिपूर्ण समाधान है जहाँ आपको चाबी आदि की आवश्यकता नहीं है ...
GWR

5

किसी तालिका की पूर्ण स्क्रिप्ट बनाने के लिए यह संभव नहीं है कि T-SQL संभव हो। कम से कम वहाँ कोई रास्ता नहीं है। आप हमेशा सूचना के माध्यम से अपने स्वयं के "जनरेटर" लिख सकते हैं sys.columns

लेकिन आपके मामले में आपको पूरी स्क्रिप्ट बनाने की आवश्यकता नहीं है। बस आपको SELECT INTOपहचान की संपत्ति की नकल करने से रोकना होगा । ऐसा करने का सबसे आसान तरीका उस कॉलम में गणना जोड़ना है। इसलिए इसके बजाय

select * into #tmp from Database1.dbo.Table1 where 1=0

आपको लिखने की जरूरत है

select id*0 as id, other, column, names into #tmp from Database1.dbo.Table1 where 1=0

इस कथन को जनरेट करने के लिए आप फिर से इस SQL फिडेल की तरह sys.columns का उपयोग कर सकते हैं

एमएस SQL ​​सर्वर 2008 स्कीमा सेटअप :

CREATE TABLE dbo.testtbl(
    id INT IDENTITY(1,1),
    other NVARCHAR(MAX),
    [column] INT,
    [name] INT
);

हमें जिन दो स्तंभों की आवश्यकता है वे हैं : nameऔर प्रश्न 1 :is_identity

SELECT name,is_identity
  FROM sys.columns
 WHERE object_id = OBJECT_ID('dbo.testtbl');

परिणाम :

|   NAME | IS_IDENTITY |
|--------|-------------|
|     id |           1 |
|  other |           0 |
| column |           0 |
|   name |           0 |

इसके साथ हम CASEकॉलम सूची के लिए प्रत्येक कॉलम बनाने के लिए एक स्टेटमेंट का उपयोग कर सकते हैं :

क्वेरी 2 :

SELECT ','+ 
    CASE is_identity
    WHEN 1 THEN QUOTENAME(name)+'*0 AS '+QUOTENAME(name)
    ELSE QUOTENAME(name)
    END
  FROM sys.columns
 WHERE object_id = OBJECT_ID('dbo.testtbl');

परिणाम :

|        COLUMN_0 |
|-----------------|
| ,[id]*0 AS [id] |
|        ,[other] |
|       ,[column] |
|         ,[name] |

थोड़ी एक्सएमएल प्रवंचना के साथ हम पूर्ण कॉलम सूची प्राप्त करने के लिए इस सब को एक साथ जोड़ सकते हैं:

प्रश्न 3 :

SELECT STUFF((
  SELECT ','+ 
      CASE is_identity
      WHEN 1 THEN QUOTENAME(name)+'*0 AS '+QUOTENAME(name)
      ELSE QUOTENAME(name)
      END
    FROM sys.columns
   WHERE object_id = OBJECT_ID('dbo.testtbl')
   ORDER BY column_id
     FOR XML PATH(''),TYPE
  ).value('.','NVARCHAR(MAX)'),1,1,'')

परिणाम :

|                               COLUMN_0 |
|----------------------------------------|
| [id]*0 AS [id],[other],[column],[name] |

ध्यान रखें, कि आप डायनेमिक SQL का उपयोग करके एक # टेबल टेबल नहीं बना सकते हैं और इसका उपयोग उस स्टेटमेंट के बाहर भी कर सकते हैं, जब आपका डायनामिक एसक्यूएल स्टेटमेंट खत्म हो जाता है। तो आपको या तो अपने सभी कोड को एक ही गतिशील SQL स्ट्रिंग में निचोड़ना होगा या एक वास्तविक तालिका का उपयोग करना होगा। यदि आपको एक ही समय में इन लिपियों / प्रक्रियाओं में से कई को निष्पादित करने में सक्षम होने की आवश्यकता है, तो आपको एक यादृच्छिक तालिका नाम की आवश्यकता है, अन्यथा वे एक-दूसरे पर कदम रखेंगे। जैसे कुछ QUOTENAME(N'temp_'+CAST(NEWID() AS NVARCHAR(40))अच्छा पर्याप्त नाम बनाना चाहिए।


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


1
आप एक # तालिका बना सकते हैं और फिर इसे डायनेमिक SQL से ठीक रेफर कर सकते हैं। यह केवल तभी है जब आप इसे उस दायरे में बनाते हैं जो गतिशील SQL द्वारा निष्पादित होने के बाद दिखाई नहीं देता है।
हारून बर्ट्रेंड

3

SQLServerCentral आलेख में इसे प्राप्त करने के लिए एक अच्छी स्क्रिप्ट है:

स्क्रिप्ट का वर्तमान नवीनतम संस्करण यहां पाठ के रूप में भी उपलब्ध है (storm.com)।

काश, यहां सभी स्क्रिप्ट को शामिल करने का एक तरीका होता, क्योंकि यह मेरे लिए काम करता है। स्क्रिप्ट को यहां पेस्ट करने के लिए बहुत लंबा है।

सर्वाधिकार सूचना:

--#################################################################################################
-- copyright 2004-2013 by Lowell Izaguirre scripts*at*stormrage.com all rights reserved.
-- http://www.stormrage.com/SQLStuff/sp_GetDDL_Latest.txt
--Purpose: Script Any Table, Temp Table or Object
--
-- see the thread here for lots of details: http://www.sqlservercentral.com/Forums/Topic751783-566-7.aspx

-- You can use this however you like...this script is not rocket science, but it took a bit of work to create.
-- the only thing that I ask
-- is that if you adapt my procedure or make it better, to simply send me a copy of it,
-- so I can learn from the things you've enhanced.The feedback you give will be what makes
-- it worthwhile to me, and will be fed back to the SQL community.
-- add this to your toolbox of helpful scripts.
--#################################################################################################

-1

आप CREATE TABLEडेटा से डायनेमिक SQL का उपयोग करके रफ उत्पन्न कर सकते हैं INFORMATION_SCHEMA.COLUMNS

यदि आपको बाधाओं आदि को जोड़ने की आवश्यकता है तो आपको कुछ अन्य INFORMATION_SCHEMAविचारों से जानकारी जोड़ने की आवश्यकता होगी ।

Microsoft प्रलेखन

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.