2011-07-06 16 views
7

मैं एक परियोजना पर काम कर रहा हूं और चयन INTO का उपयोग करते समय कुछ रोचक व्यवहार में आया हूं। अगर मेरे पास int identity(1,1) not null के रूप में परिभाषित कॉलम वाला एक टेबल है और इसे कॉपी करने के लिए चयन करें INTO का उपयोग करें, तो नई तालिका पहचानकर्ता संपत्ति को तब तक बनाए रखेगी जब तक कोई शामिल न हो। यदि कोई जुड़ाव है, तो नई तालिका पर एक ही कॉलम को int not null के रूप में परिभाषित किया गया है।व्यवहार और पहचान संपत्ति में चयन करें

CREATE TABLE People (Id INT IDENTITY(1,1) not null, Name VARCHAR(10)) 
CREATE TABLE ReverseNames (Name varchar(10), ReverseName varchar(10)) 

INSERT INTO People (Name) 
VALUES ('John'), ('Jamie'), ('Joe'), ('Jenna') 

INSERT INTO ReverseNames (Name, ReverseName) 
VALUES ('John','nhoJ'), ('Jamie','eimaJ'), ('Joe','eoJ'), ('Jenna','anneJ') 

-------- 

SELECT Id, Name 
INTO People_ExactCopy 
FROM People 

SELECT Id, ReverseName as Name 
INTO People_WithJoin 
FROM People 
    JOIN ReverseNames 
     ON People.Name = ReverseNames.Name 

SELECT Id, (SELECT ReverseName FROM ReverseNames WHERE Name = People.Name) as Name 
INTO People_WithSubSelect 
FROM People 

-------- 

SELECT OBJECT_NAME(c.object_id) as [Table], 
    c.is_identity as [Id Column Retained Identity] 
FROM sys.columns c 
where 
OBJECT_NAME(c.object_id) IN ('People_ExactCopy','People_WithJoin','People_WithSubSelect') 
    AND c.name = 'Id' 

-------- 

DROP TABLE People 
DROP TABLE People_ExactCopy 
DROP TABLE People_WithJoin 
DROP TABLE People_WithSubSelect 
DROP TABLE ReverseNames 

मैंने देखा है कि दोनों WithJoin और WithSubSelect प्रश्नों के लिए निष्पादन की योजना एक ऑपरेटर में शामिल होने का समावेश है:

यहाँ एक स्क्रिप्ट है कि आप व्यवहार पुन: पेश करने चला सकते है। मुझे यकीन नहीं है कि अगर हम पंक्तियों के बड़े सेट से निपट रहे थे तो प्रदर्शन पर कोई बेहतर प्रदर्शन करेगा।

क्या कोई इस पर कोई प्रकाश डाल सकता है और मुझे बता सकता है कि क्या जुड़ने के साथ चयन का उपयोग करने का कोई तरीका है और फिर भी पहचान संपत्ति को सुरक्षित रखता है?

उत्तर

7

Microsoft से:

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

The SELECT statement contains a join, GROUP BY clause, or aggregate 

फ़ंक्शन।

Multiple SELECT statements are joined by using UNION. 

The identity column is listed more than one time in the select list. 

The identity column is part of an expression. 

The identity column is from a remote data source. 

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

आप IDENTITY समारोह के रूप में इस्तेमाल कर सकते हैं वे सुझाव देते हैं और IDENTITY स्तंभ को छोड़ देते हैं, लेकिन फिर आप मान खो देगा, के रूप में IDENTITY समारोह नए मूल्यों उत्पन्न होगा और मुझे लगता है कि नहीं है कि उन लोगों के लिए आसानी से निर्धारण कर रहे हैं, यहां तक ​​कि ORDER BY के साथ।

+0

"मुझे नहीं लगता कि वे आसानी से निर्धारणीय हैं" मैं यह असंभव कहूंगा कि आईडी फ़ील्ड में –

+0

अंतराल में एक ही चयन में मुझे नहीं लगता कि आपको यह समस्या होगी। पहचान कॉलम में अंतर आमतौर पर एकाधिक प्रविष्टियों के बीच होने वाली रोलबैक के कारण होते हैं। समस्या यह है कि आईडी को क्वेरी प्लान में कहीं भी जेनरेट किया जा सकता है, जिसका मतलब किसी भी क्रम में जरूरी नहीं है। –

+0

'चयन करें' जस्टिन के उदाहरण का उपयोग करते हुए 'सेट आईडीएनटीआईसीएसईआरटी ऑन' के समतुल्य है यदि आप 'सेलेक्ट्स' से पहले नाम 'नाम' से पहले नाम हटाएं, जो और 'जेमी' आईडी और 3 के आईडी को बनाए रखता है। फ़ंक्शन इसे संरक्षित नहीं करेगा। आप प्रत्येक 5 सेकंड में केवल एक टिप्पणी संपादित कर सकते हैं। (इस बॉक्स पर खारिज करने के लिए क्लिक करें) –

2

मुझे विश्वास नहीं है कि आप अपने क्रिएट टेबल स्टेटमेंट मैन्युअल रूप से सेट करने के अलावा, मौजूदा मानों को सम्मिलित करने के बाद, सेट IDENTITY_INSERT OFF को छोड़कर, आप कर सकते हैं। हां आप चयन में लाभ खो देते हैं, लेकिन जब तक कि आपकी टेबल बड़ी न हों और आप इसे बहुत कुछ कर रहे हैं, [शग]।यह निश्चित रूप से मजेदार नहीं है, और यह चयन के रूप में सुंदर या सरल नहीं है, लेकिन आप इसे कुछ हद तक प्रोग्रामेटिक रूप से कर सकते हैं, जिसमें दो टेबल हैं, एक सरल पहचान (1,1), और सरल INNER JOIN :

SET NOCOUNT ON; 

DECLARE 
    @NewTable SYSNAME = N'dbo.People_ExactCopy', 
    @JoinCondition NVARCHAR(255) = N' ON p.Name = r.Name'; 

DECLARE 
    @cols TABLE(t SYSNAME, c SYSNAME, p CHAR(1)); 

INSERT @cols SELECT N'dbo.People', N'Id', 'p' 
    UNION ALL SELECT N'dbo.ReverseNames', N'Name', 'r'; 

DECLARE @sql NVARCHAR(MAX) = N'CREATE TABLE ' + @NewTable + ' 
(
'; 

SELECT @sql += c.name + ' ' + t.name 
    + CASE WHEN t.name LIKE '%char' THEN 
     '(' + CASE WHEN c.max_length = -1 
      THEN 'MAX' ELSE RTRIM(c.max_length/ 
      (CASE WHEN t.name LIKE 'n%' THEN 2 ELSE 1 END)) END 
     + ')' ELSE '' END 
    + CASE c.is_identity 
    WHEN 1 THEN ' IDENTITY(1,1)' 
    ELSE ' ' END + ', 
    ' 
    FROM sys.columns AS c 
    INNER JOIN @cols AS cols 
    ON c.object_id = OBJECT_ID(cols.t) 
    INNER JOIN sys.types AS t 
    ON c.system_type_id = t.system_type_id 
    AND c.name = cols.c; 

SET @sql = LEFT(@sql, LEN(@sql)-1) + ' 
); 

SET IDENTITY_INSERT ' + @NewTable + ' ON; 

INSERT ' + @NewTable + '('; 

SELECT @sql += c + ',' FROM @cols; 

SET @sql = LEFT(@sql, LEN(@sql)-1) + ') 
    SELECT '; 

SELECT @sql += p + '.' + c + ',' FROM @cols; 

SET @sql = LEFT(@sql, LEN(@sql)-1) + ' 
    FROM '; 

SELECT @sql += t + ' AS ' + p + ' 
    INNER JOIN ' FROM (SELECT DISTINCT 
     t,p FROM @cols) AS x; 

SET @sql = LEFT(@sql, LEN(@sql)-10) 
    + @JoinCondition + '; 

SET IDENTITY_INSERT ' + @NewTable + ' OFF;'; 

PRINT @sql; 

ऊपर दिए गए टेबल के साथ, इस निम्नलिखित है, जो आप प्रिंट के बजाय EXEC sp_executesql के लिए दे सकते हैं पैदा करता है:

CREATE TABLE dbo.People_ExactCopy 
(
    Id int IDENTITY(1,1), 
    Name varchar(10) 
); 

SET IDENTITY_INSERT dbo.People_ExactCopy ON; 

INSERT dbo.People_ExactCopy(Id,Name) 
    SELECT p.Id,r.Name 
    FROM dbo.People AS p 
    INNER JOIN dbo.ReverseNames AS r 
    ON p.Name = r.Name; 

SET IDENTITY_INSERT dbo.People_ExactCopy OFF; 

मैं ऐसे दशमलव कॉलम या अन्य रूप में अन्य जटिलताओं से निपटने के नहीं था कॉलम जिनमें अधिकतम_लेथेंथ जैसे पैरामीटर हैं, न ही मैंने डब्ल्यू को सौदा किया था ith शून्यता, लेकिन अगर आपको अधिक लचीलापन की आवश्यकता है तो इन चीजों को जोड़ना मुश्किल नहीं होगा।

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

हमें वास्तव में क्या चाहिए डीडीएल है जो आपको कुछ कहने की अनुमति देता है "तालिका को पहचानने के लिए एक आदर्श बनाएं;" या "तालिका को आधार पर तैयार करें;" ... यहां से पूछा गया है, लेकिन इसे अस्वीकार कर दिया गया है (यह एक तालिका को दूसरी स्कीमा में कॉपी करने के बारे में है, लेकिन एक ही अवधारणा एक ही स्कीमा में एक नई तालिका पर लागू हो सकती है अलग टेबल नाम)। http://connect.microsoft.com/SQLServer/feedback/details/632689

0

मुझे पता है यह एक बहुत देर से प्रतिक्रिया है लेकिन जो कोई भी अभी भी, जब तक मैं इस समाधान इस समाधान की तलाश में है जैसे मैं था:

आप पहचान स्तंभ संपत्ति के लिए ऑपरेटर शामिल हों उपयोग नहीं कर सकते होने के लिए विरासत में मिला। आप क्या कर सकते हैं, जहां इस तरह खंड एक का उपयोग करें:। से MyTable NewTable जांच

एक का चयन करें * एक कहां मौजूद है (SecondTable बी से 1 का चयन करें जहां b.ID = a.ID)

यह काम करता है।

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