किसी तालिका में एक स्तंभ से पहचान निकालें


127

हमारे पास 5GB तालिका (लगभग 500 मिलियन पंक्तियाँ) हैं और हम कॉलम में से एक पर पहचान संपत्ति को हटाना चाहते हैं, लेकिन जब हम SSMS के माध्यम से ऐसा करने का प्रयास करते हैं - यह समय समाप्त हो जाता है।

क्या यह टी-एसक्यूएल के माध्यम से किया जा सकता है?


1
क्या आप यहां तालिका का स्कीमा पोस्ट कर सकते हैं?
अल डब्ल्यू

मुझे यकीन है कि ऐसे उत्कृष्ट कारण हैं कि SQL सर्वर एक कॉलम से एक पहचान संपत्ति को हटाने के लिए एक साधारण तालिका ... कथन के माध्यम से समर्थन नहीं करता है, लेकिन यह अभी भी मुझे दुखी कर रहा है कि मामला है।
जॉन श्नाइडर

जवाबों:


143

आप एक IDENTITYबार सेट किए गए विनिर्देश को नहीं निकाल सकते ।

संपूर्ण स्तंभ को निकालने के लिए:

ALTER TABLE yourTable
DROP COLUMN yourCOlumn;

ALTER TABLE के बारे में जानकारी यहाँ

यदि आपको डेटा रखने की आवश्यकता है, लेकिन IDENTITYकॉलम को हटा दें , तो आपको निम्न करना होगा:

  • एक नया कॉलम बनाएं
  • मौजूदा IDENTITYकॉलम से नए कॉलम में डेटा ट्रांसफर करें
  • मौजूदा IDENTITYकॉलम ड्रॉप करें।
  • नए कॉलम को मूल कॉलम नाम से बदलें

3
आप एक पहचान युक्ति निकाल सकते हैं। वास्तव में मुझे कल यह SSMS का उपयोग करके करना था, हालांकि 500 ​​मिलियन पंक्तियों पर नहीं।
साइमन

33
@simon यदि आप अपने परिवर्तनों को स्क्रिप्ट करते हैं, तो आप देखेंगे कि SSMS वास्तव में पहचान की संपत्ति w / o तालिका की एक प्रति बना रहा है।
कोड जादूगर

3
मैं मूल स्तंभ के नाम में नए कॉलम का नाम जोड़ना चाहता हूं। इसके अलावा, यदि इस identityस्तंभ का उपयोग foreign keyकिसी अन्य तालिका के भाग के रूप में किया जाता है , तो आपको पहले बाधाओं को छोड़ना होगा, फिर कार्यवाही करें क्योंकि पहचान हटाने के बारे में @AdamWenger ने उल्लेख किया है। attribute/propertyआप अधिक जानकारी के लिए इस लिंक पर भी देख सकते हैं केवल विशेषता को हटाने के बारे में: blog.sqlauthority.com/2009/05/03/… ..Good किस्मत!
नॉनिम

1
नीचे मतदान करने वाले व्यक्ति के लिए - मैं यह सुनकर सराहना करूंगा कि आपको मेरे उत्तर के बारे में क्या पसंद नहीं आया।
एडम वेंगर

1
नीचे दिए गए मार्क सोउल के जवाब पर एक नज़र डालें। स्तंभ से स्तंभ तक डेटा ले जाने की आवश्यकता को रोकता है। मार्क के उत्तर का उपयोग करके आप केवल मेटाडेटा फेरबदल कर रहे हैं। जब तक आप एक मेज पर काम नहीं कर रहे हैं जिसमें दसियों या सैकड़ों लाखों पंक्तियाँ हैं। प्लस मार्क का जवाब तालिका स्कीमा में कॉलम के स्थानांतरण को रोकता है। मैंने बस कोशिश की और यह एक आकर्षण की तरह काम किया। बहुत चालाक।
एंड्रयू स्टिट्ज

100

यदि आप स्तंभों को पुन: व्यवस्थित किए बिना , एक नया कॉलम जोड़ और आबाद किए बिना ऐसा करना चाहते हैं , और लगभग कोई डाउनटाइम नहीं है क्योंकि कोई भी डेटा टेबल पर नहीं बदल रहा है, तो आइए विभाजन विभाजन कार्यक्षमता के साथ कुछ जादू करें (लेकिन चूंकि कोई विभाजन आप उपयोग नहीं करते हैं ' टी एंटरप्राइज संस्करण की आवश्यकता):

  1. इस तालिका को इंगित करने वाली सभी विदेशी कुंजियों को निकालें
  2. बनाई जाने वाली तालिका को स्क्रिप्ट करें; 'MyTable2', 'MyIndex2', आदि जैसे सभी चीजों का नाम बदलें।
  3. अब आपके पास दो "समान" -इश टेबल होनी चाहिए, एक पूर्ण, दूसरा बिना किसी पहचान के खाली।
  4. Daud ALTER TABLE [Original] SWITCH TO [Original2]
  5. अब आपकी मूल तालिका खाली हो जाएगी और नए के पास डेटा होगा। आपने मेटाडेटा को दो तालिकाओं (तत्काल) में बदल दिया है।
  6. मूल (अब-खाली तालिका) exec sys.sp_renameको छोड़ें, विभिन्न स्कीमा वस्तुओं को वापस मूल नामों में बदलने के लिए, और फिर आप इन विदेशी कुंजियों को फिर से बना सकते हैं।

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

CREATE TABLE Original
(
  Id INT IDENTITY PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value ON Original (Value);

INSERT INTO Original
SELECT 'abcd'
UNION ALL 
SELECT 'defg';

आप निम्न कार्य कर सकते हैं:

--create new table with no IDENTITY
CREATE TABLE Original2
(
  Id INT PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value2 ON Original2 (Value);

--data before switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

ALTER TABLE Original SWITCH TO Original2;

--data after switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

--clean up 
IF NOT EXISTS (SELECT * FROM Original) DROP TABLE Original;
EXEC sys.sp_rename 'Original2.IX_Original_Value2', 'IX_Original_Value', 'INDEX';
EXEC sys.sp_rename 'Original2', 'Original', 'OBJECT';


UPDATE Original
SET Id = Id + 1;

SELECT *
FROM Original;

मेरे पास वास्तव में यह कोशिश करने के लिए समय नहीं है, लेकिन अगली बार जब मुझे वास्तव में एक पहचान छोड़ने की आवश्यकता है, तो यह जानना अच्छी बात है।
कोडरडेन

11
यह स्वीकृत उत्तर होना चाहिए। बड़े पैमाने पर डेटा माइग्रेशन के बिना एक पहचान कॉलम को हटाने का एकमात्र वास्तविक तरीका है।
वैकैनो

वाह! यह बहुत चालाक है।
एंड्रयू स्टिट्ज

यह जवाब अभूतपूर्व है! धन्यवाद!
जॉन

5
यदि तालिका से बाहर स्क्रिप्ट करने के लिए SQL प्रबंधन स्टूडियो का उपयोग किया जाता है, तो उपकरण> विकल्प> SQL सर्वर ऑब्जेक्ट एक्सप्लोरर> स्क्रिप्टिंग> तालिका और दृश्य विकल्प> स्क्रिप्ट इंडेक्स (डिफ़ॉल्ट रूप से गलत)
234 बजे उपयोगकर्ता 1423430

61

यह विदेशी और प्राथमिक महत्वपूर्ण बाधाओं के साथ गड़बड़ हो जाता है, इसलिए यहां आपके रास्ते में मदद करने के लिए कुछ स्क्रिप्ट हैं:

सबसे पहले, एक अस्थायी नाम के साथ एक डुप्लिकेट कॉलम बनाएं:

alter table yourTable add tempId int NOT NULL default -1;
update yourTable set tempId = id;

इसके बाद, अपने प्राथमिक कुंजी बाधा का नाम प्राप्त करें:

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'yourTable';

अब अपने कॉलम के लिए प्राथमिक मुख्य बाधा छोड़ने की कोशिश करें:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;

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

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'otherTable';
alter table otherTable drop constraint fk_otherTable_yourTable;
commit;
..

एक बार जब आपकी सभी विदेशी कुंजी बाधाएं हटा दी जाती हैं, तो आप PK बाधा को दूर करने में सक्षम होंगे, उस कॉलम को छोड़ देंगे, अपने अस्थायी कॉलम का नाम बदल देंगे, और उस कॉलम में PK बाधा को जोड़ सकते हैं:

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;
alter table yourTable drop column id;
EXEC sp_rename 'yourTable.tempId', 'id', 'COLUMN';
ALTER TABLE yourTable ADD CONSTRAINT PK_yourTable_id PRIMARY KEY (id) 
commit;

अंत में, वापस FK बाधाओं को जोड़ें:

alter table otherTable add constraint fk_otherTable_yourTable foreign key (yourTable_id) references yourTable(id);
..

एल फिन!


अपने sql सर्वर संस्करण पर ध्यान दें, मैंने azure sql सर्वर में कोशिश की, यहाँ सभी ऑपरेशन azure संस्करण sql में समर्थित नहीं हैं।
दासों

जवाब के लिए धन्यवाद! मेरी बहुत मदद की! आपको बस उन संदर्भों के लिए एक सत्यापन जोड़ना चाहिए जो स्तंभ को संदर्भित करते हैं। कुछ इस तरह: Select t.name 'Table', i.name 'Index', c.name 'Column', i.is_primary_key, i.is_unique From sys.tables t Inner Join sys.indexes i On i.object_id = t.object_id Inner Join sys.index_columns ic ON ic.object_id = i.object_id And i.index_id = ic.index_id Inner Join sys.columns c ON ic.object_id = c.object_id and ic.column_id = c.column_id Where t.name = 'tableName' Order By t.name, i.name, i.index_id, ic.index_column_id
अलेक्जेंड्रे जंगेस

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

19

मुझे बस यही समस्या थी। GUI का उपयोग करने के बजाय SSMS में 4 कथन और यह बहुत तेज था।

  • एक नया कॉलम बनाएं

    alter table users add newusernum int;

  • मूल्यों को कॉपी करें

    update users set newusernum=usernum;

  • पुराना कॉलम ड्रॉप करें

    alter table users drop column usernum;

  • पुराने कॉलम के नाम पर नए कॉलम का नाम बदलें

    EXEC sp_RENAME 'users.newusernum' , 'usernum', 'COLUMN';


यदि आपके पास पुराने कॉलम पर कोई अड़चन है तो यह सरल नहीं है।
सनकैट २२

13

स्क्रिप्ट के बाद 'Id' नामक एक कॉलम के लिए पहचान क्षेत्र को हटा देता है

आशा करता हूँ की ये काम करेगा।

BEGIN TRAN
BEGIN TRY
    EXEC sp_rename '[SomeTable].[Id]', 'OldId';

    ALTER TABLE [SomeTable] ADD Id int NULL

    EXEC ('UPDATE [SomeTable] SET Id = OldId')

    ALTER TABLE [SomeTable] NOCHECK CONSTRAINT ALL

    ALTER TABLE [SomeTable] DROP CONSTRAINT [PK_constraintName];
    ALTER TABLE [SomeTable] DROP COLUMN OldId
    ALTER TABLE [SomeTable] ALTER COLUMN [Id] INTEGER NOT NULL
    ALTER TABLE [SomeTable] ADD CONSTRAINT PK_JobInfo PRIMARY KEY (Id)

    ALTER TABLE [SomeTable] CHECK CONSTRAINT ALL

    COMMIT TRAN
END TRY
BEGIN CATCH
    ROLLBACK TRAN   
    SELECT ERROR_MESSAGE ()
END CATCH

4

जब हम पहचान कॉलम का नाम नहीं जानते हैं, तो बलो कोड ठीक काम करता है ।

जैसे नए अस्थायी तालिका में डेटा की प्रतिलिपि बनाने की आवश्यकता है Invoice_DELETED। और अगली बार हम उपयोग कर रहे हैं:

insert into Invoice_DELETED select * from Invoice where ...


SELECT t1.*
INTO Invoice_DELETED
FROM Invoice t1
LEFT JOIN Invoice ON 1 = 0
--WHERE t1.InvoiceID = @InvoiceID

अधिक स्पष्टीकरण के लिए देखें: https://dba.stackexchange.com/a/138345/101038


1
प्यार YAAAAAAAAAA बिल्कुल वही जो मैं ढूंढ रहा था, एक "SELECT * INTO" से "IDENTITY" पैदा करने से बचने का एक आसान तरीका (बैकअप के लिए एक नया टेबल
टेम्प

यह छोटा और सौंदर्य है;)
ज़ोल्फ़ागारी

3
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'

हालांकि उपरोक्त कोड केवल तभी काम करता है जब कोई प्राथमिक-विदेशी कुंजी संबंध न हो


1

बस किसी के लिए जो मुझे वही समस्या है। अगर आप सिर्फ एक बार कुछ डालना चाहते हैं तो आप कुछ ऐसा कर सकते हैं।

मान लें कि आपके पास एक तालिका है जिसमें दो कॉलम हैं

ID Identity (1,1) | Name Varchar

और ID = 4. के साथ एक पंक्ति सम्मिलित करना चाहते हैं। इसलिए आपने इसे 3 पर Reseed किया ताकि अगला 4 हो

DBCC CHECKIDENT([YourTable], RESEED, 3)

सम्मिलित करें

INSERT  INTO [YourTable]
        ( Name )
VALUES  ( 'Client' )

और अपने बीज को उच्चतम आईडी पर वापस लाएं, मान लें कि यह 15 है

DBCC CHECKIDENT([YourTable], RESEED, 15)

किया हुआ!


1

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

/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION

SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.SI_Provider_Profile
    DROP CONSTRAINT DF_SI_Provider_Profile_SIdtDateTimeStamp
GO
ALTER TABLE dbo.SI_Provider_Profile
    DROP CONSTRAINT DF_SI_Provider_Profile_SIbHotelPreLoaded
GO
CREATE TABLE dbo.Tmp_SI_Provider_Profile
    (
    SI_lProvider_Profile_ID int NOT NULL,
    SI_lSerko_Integrator_Token_ID int NOT NULL,
    SI_sSerko_Integrator_Provider varchar(50) NOT NULL,
    SI_sSerko_Integrator_Profile varchar(50) NOT NULL,
    SI_dtDate_Time_Stamp datetime NOT NULL,
    SI_lProvider_ID int NULL,
    SI_sDisplay_Name varchar(10) NULL,
    SI_lPurchased_From int NULL,
    SI_sProvider_UniqueID varchar(255) NULL,
    SI_bHotel_Pre_Loaded bit NOT NULL,
    SI_sSiteName varchar(255) NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile SET (LOCK_ESCALATION = TABLE)
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
    DF_SI_Provider_Profile_SIdtDateTimeStamp DEFAULT (getdate()) FOR SI_dtDate_Time_Stamp
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
    DF_SI_Provider_Profile_SIbHotelPreLoaded DEFAULT ((0)) FOR SI_bHotel_Pre_Loaded
GO
IF EXISTS(SELECT * FROM dbo.SI_Provider_Profile)
        EXEC('INSERT INTO dbo.Tmp_SI_Provider_Profile (SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName)
        SELECT SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName FROM dbo.SI_Provider_Profile WITH (HOLDLOCK TABLOCKX)')
GO

-- Rename the primary key constraint or unique key In SQL Server constraints such as primary keys or foreign keys are objects in their own right, even though they are dependent upon the "containing" table.
EXEC sp_rename 'dbo.SI_Provider_Profile.PK_SI_Provider_Profile', 'PK_SI_Provider_Profile_Old';
GO
-- backup old table in case of 
EXECUTE sp_rename N'dbo.SI_Provider_Profile', N'SI_Provider_Profile_Old', 'OBJECT'
GO

EXECUTE sp_rename N'dbo.Tmp_SI_Provider_Profile', N'SI_Provider_Profile', 'OBJECT'
GO

ALTER TABLE dbo.SI_Provider_Profile ADD CONSTRAINT
    PK_SI_Provider_Profile PRIMARY KEY NONCLUSTERED 
    (
    SI_lProvider_Profile_ID
    ) WITH( PAD_INDEX = OFF, FILLFACTOR = 90, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT TRANSACTION

1

SQL सर्वर में आप इस तरह पहचान डालने को चालू और बंद कर सकते हैं:

IDENTITY_INSERT तालिका सेट करें

- अपने प्रश्नों को यहां चलाएं

IDENTITY_INSERT तालिका सेट करें_नाम बंद करें

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