मैं SELECT INTO वाली तालिका की प्रतिलिपि कैसे बना सकता हूं लेकिन पहचान की संपत्ति की उपेक्षा नहीं करता?


41

मेरे पास पहचान स्तंभ के साथ एक तालिका है:

create table with_id (
 id int identity(1,1),
 val varchar(30)
);

यह अच्छी तरह से ज्ञात है, कि यह

select * into copy_from_with_id_1 from with_id;

id पर पहचान के साथ copy_from_with_id_1 में परिणाम।

निम्नलिखित स्टैक ओवरफ़्लो प्रश्न में स्पष्ट रूप से सभी कॉलमों को सूचीबद्ध करने का उल्लेख है।

कोशिश करते हैं

select id, val into copy_from_with_id_2 from with_id;

ओह, इस मामले में भी आईडी एक पहचान स्तंभ है।

मुझे जो चाहिए वो है जैसे टेबल

create table without_id (
 id int,
 val varchar(30)
);

जवाबों:


52

ऑनलाइन पुस्तकों से

चयन सूची में भावों का मूल्यांकन करके new_table का प्रारूप निर्धारित किया जाता है। New_table में कॉलम चुनिंदा सूची द्वारा निर्दिष्ट क्रम में बनाए गए हैं। New_table में प्रत्येक कॉलम का नाम, डेटा प्रकार, अशक्तता और मान के रूप में चयन सूची में संबंधित अभिव्यक्ति है। रिमार्क्स अनुभाग में "पहचान कॉलम के साथ काम करना" में परिभाषित शर्तों के तहत एक स्तंभ की पहचान संपत्ति को स्थानांतरित किया जाता है।

पृष्ठ के नीचे:

जब एक मौजूदा पहचान स्तंभ को एक नई तालिका में चुना जाता है, तो नया स्तंभ पहचान की संपत्ति प्राप्त करता है, जब तक कि निम्न में से कोई एक स्थिति सत्य न हो:

  • SELECT स्टेटमेंट में एक Join, GROUP BY क्लॉज या एग्रीगेट फंक्शन शामिल होता है।
  • एकाधिक चयन बयान UNION का उपयोग करके शामिल हो गए हैं।
  • पहचान कॉलम को चयनित सूची में एक से अधिक बार सूचीबद्ध किया गया है।
  • पहचान स्तंभ एक अभिव्यक्ति का हिस्सा है।
  • पहचान स्तंभ दूरस्थ डेटा स्रोत से है।

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

इसलिए ... आप सैद्धांतिक रूप से दूर हो सकते हैं:

select id, val 
into copy_from_with_id_2 
from with_id

union all

select 0, 'test_row' 
where 1 = 0;

इस कोड को समझाने के लिए यह टिप्पणी करना महत्वपूर्ण होगा, ऐसा न हो कि अगली बार जब कोई इसे देखता है तो इसे हटा दिया जाए।


29

एरिक्सन के उत्तर से प्रेरित होकर, मैंने निम्नलिखित समाधान पाया जो केवल तालिका के नामों पर निर्भर करता है और किसी विशिष्ट कॉलम नाम का उपयोग नहीं करता है:

select * into without_id from with_id where 1 = 0
union all
select * from with_id where 1 = 0
;
insert into without_id select * from with_id;

संपादित करें

इसे सुधारना और भी संभव है

select * into without_id from with_id
union all
select * from with_id where 1 = 0
;

13

आप नई तालिका को एक बार में बनाने और आबाद करने के लिए एक प्रयोग का उपयोग कर सकते हैं:

SELECT
  t.*
INTO
  dbo.NewTable
FROM
  dbo.TableWithIdentity AS t
  LEFT JOIN dbo.TableWithIdentity ON 1 = 0
;

की वजह से 1 = 0हालत, दाईं ओर कोई मेल नहीं होगा और इस तरह बाईं ओर पंक्तियों के दोहराव को रोकने, और क्योंकि यह एक बाहरी में शामिल होने है, बाईं ओर पंक्तियों या तो समाप्त नहीं किया जाएगा। अंत में, क्योंकि यह एक सम्मिलित है, इसलिए पहचान की संपत्ति समाप्त हो गई है।

इसलिए, केवल बाईं ओर के स्तंभों का चयन करना, केवल dbo.TableWithIdentity डेटा-वार की एक सटीक प्रतिलिपि का उत्पादन करेगा , यानी IDENTITY संपत्ति के साथ छीन लिया जाएगा।

कहा जा रहा है कि मैक्स वर्नोन ने एक टिप्पणी में एक वैध बिंदु उठाया है जो ध्यान में रखने योग्य है। यदि आप उपरोक्त क्वेरी के निष्पादन योजना को देखते हैं:

निष्पादन योजना

आप देखेंगे कि स्रोत तालिका का क्रियान्वयन योजना में सिर्फ एक बार किया गया है। अन्य उदाहरण को आशावादी द्वारा समाप्त कर दिया गया है।

इसलिए, यदि ऑप्टिमाइज़र सही ढंग से यह स्थापित कर सकता है कि योजना में शामिल होने के दाईं ओर की आवश्यकता नहीं है, तो यह अपेक्षा करना उचित होगा कि SQL सर्वर के भविष्य के संस्करण में यह पता लगाने में सक्षम हो सकता है कि पहचान की संपत्ति की आवश्यकता नहीं है या तो हटा दिया गया है, क्योंकि क्वेरी योजना के अनुसार स्रोत पंक्ति में कोई अन्य पहचान स्तंभ नहीं है। इसका मतलब है कि उपरोक्त क्वेरी कुछ बिंदु पर अपेक्षित रूप से काम करना बंद कर सकती है।

लेकिन, जैसा कि ypercubeᵀᴹ द्वारा सही ढंग से नोट किया गया है , अब तक मैनुअल स्पष्ट रूप से कह रहा है कि यदि कोई सम्मिलित है , तो पहचान की संपत्ति संरक्षित नहीं है:

जब एक मौजूदा पहचान कॉलम को एक नई तालिका में चुना जाता है, तो नया कॉलम IDENTITY संपत्ति का वारिस करता है, जब तक कि [...] [t] वह चयन कथन में सम्मिलित न हो।

इसलिए, जब तक मैनुअल इसका उल्लेख करता रहता है, हम शायद इस बात पर निश्चिंत हो सकते हैं कि व्यवहार वही रहेगा।

चैट में संबंधित विषय को लाने के लिए कुडोस से शेनिस और ypercube bringing।


चाहेंगे JOIN (SELECT 1) AS dummy ON 1 = 1काम करते हैं, भी?
ypercube y

CROSS JOIN (SELECT 1), INNER JOIN (SELECT 1) ON 1=1, LEFT JOIN (SELECT 1) ON 1=0या ON 1=1- कोई नहीं पहचान स्ट्रिप्स। ऐसा लगता है कि यह एक घोषित या बनाई गई वस्तु होनी चाहिए
एंड्री एम

5

इस कोड को आज़माएं ..

SELECT isnull(Tablename_old.IDENTITYCOL + 0, -1) AS 'New Identity Column'
INTO   dbo.TableName_new
FROM   dbo.TableName_old 

ISNULLकॉल सुनिश्चित करता है कि नया कॉलम बनाई गई है NOT NULLnullability।


1
यह है ISNULL()या +0कि यह करता है? या दोनों की जरूरत है?
ypercube y

3

बस एक अलग रास्ता दिखाने के लिए:

आप एक लिंक किए गए सर्वर का उपयोग कर सकते हैं ।

SELECT * 
INTO without_id 
FROM [linked_server].[source_db].dbo.[with_id];

आप इसका उपयोग करके अस्थायी रूप से स्थानीय सर्वर से लिंक सर्वर बना सकते हैं:

DECLARE @LocalServer SYSNAME 
SET @LocalServer = @@SERVERNAME;
EXEC master.dbo.sp_addlinkedserver @server = N'localserver'
    , @srvproduct = ''
    , @provider = 'SQLNCLI'
    , @datasrc = @LocalServer;
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'localserver'
    , @useself = N'True'
    , @locallogin = NULL
    , @rmtuser = NULL
    , @rmtpassword = NULL;

किस बिंदु पर, आप लिंक को चार सर्वर-पार्ट-नाम से select * intoसंदर्भित करते हुए कोड चलाएंगे localserver:

SELECT * 
INTO without_id 
FROM [localserver].[source_db].dbo.[with_id];

उसके पूरा होने के बाद, इससे localserverजुड़े सर्वर को साफ करें:

EXEC sp_dropserver @server = 'localserver'
    , @droplogins = 'droplogins';

या, आप OPENQUERYसिंटैक्स का उपयोग कर सकते हैं

SELECT * 
INTO without_id 
FROM OPENQUERY([linked_server], 'SELECT * FROM [source_db].dbo.[with_id]');

1

पहचान संपत्ति को स्थानांतरित नहीं किया जाता है यदि चयन स्टेटमेंट में शामिल होता है, और इसी तरह

select a.* into without_id from with_id a inner join with_id b on 1 = 0;

संपत्ति idको न रखने के लिए वांछित व्यवहार (कॉपी किए गए कॉलम का भी) देगा IDENTITY। हालांकि, इसका किसी भी पंक्ति को बिल्कुल भी कॉपी न करने का दुष्प्रभाव होगा! (कुछ अन्य तरीकों के साथ) इसलिए आपको फिर करने की आवश्यकता होगी:

insert into without_id select * from with_id;

(धन्यवाद आकाश!)


1

आसान तरीका यह है कि कॉलम को अभिव्यक्ति का हिस्सा बनाया जाए।

उदाहरण:
यदि तालिका dbo.Employee की पहचान ID कॉलम पर है तो नीचे दिए गए उदाहरण में temp टेबल #t के साथ ID कॉलम पर एक पहचान पत्र भी होगा।

--temp table has IDENTITY
select ID, Name 
into #t
from dbo.Employee

ID में एक अभिव्यक्ति लागू करने के लिए इसे बदलें और आप #t के पास अब ID कॉलम पर कोई पहचान नहीं होगी। इस मामले में हम आईडी कॉलम के लिए एक सरल जोड़ लागू करते हैं।

--no IDENTITY
select ID = ID + 0, Name 
into #t
from dbo.Employee

अन्य डेटा प्रकारों के लिए अभिव्यक्तियों के अन्य उदाहरणों में शामिल हो सकते हैं: रूपांतरित करना (), स्ट्रिंग संयोजन, या इसनुल ()


1
से docs.microsoft.com/en-us/sql/t-sql/queries/... : "जब एक मौजूदा पहचान स्तंभ एक नई तालिका में चुना जाता है, नया स्तंभ पहचान संपत्ति, विरासत में जब तक निम्न स्थितियों में से कोई एक सही ... पहचान स्तंभ एक अभिव्यक्ति का हिस्सा है ... स्तंभ को पहचान की संपत्ति प्राप्त करने के बजाय NULL नहीं बनाया गया है। "
Manngo

1

कभी-कभी, आप उस तालिका से सम्मिलित करना चाहते हैं जहाँ आप नहीं जानते (या देखभाल) कि स्तंभ पहचान का उपयोग करके बनाया गया था या नहीं। यह पूर्णांक स्तंभ भी नहीं हो सकता है, जिसके साथ आप काम कर रहे हैं। इस मामले में, निम्नलिखित काम करेगा:

SELECT TOP(0) ISNULL([col],NULL) AS [col], ... INTO [table2] FROM [table1]
ALTER TABLE [table2] REBUILD WITH (DATA_COMPRESSION=page)
INSERT INTO [table2] ...

ISNULL स्तंभ से IDENTITY विशेषता को छोड़ देगा, लेकिन इसे उसी नाम के साथ सम्मिलित करेगा और मूल स्तंभ के रूप में टाइप करेगा और इसे भी अशक्त नहीं बना सकता है। TOP (0) एक खाली तालिका बनाएगा जिसका उपयोग आप चयनित पंक्तियों को सम्मिलित करने के लिए कर सकते हैं। आवश्यकता पड़ने पर डेटा डालने से पहले आप तालिका को संकुचित भी कर सकते हैं।


0
select convert(int, id) as id, val 
into copy_from_with_id_without_id 
from with_id;

पहचान हटा देंगे।

नकारात्मक पक्ष यह है कि idअशक्त हो जाता है लेकिन आप उस बाधा को जोड़ सकते हैं।


1
आप उस के आसपास पाने के लिए ISNULL का उपयोग कर सकते हैं ।
एरिक डार्लिंग

-2

तुम नहीं। select * intoपहचान बरकरार रखता है।


2
उपयोग करने के लिए प्रश्न में कोई आवश्यकता नहीं थी *
मार्टिन स्मिथ

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