मौजूदा पीके में ऑटोइंक्रिमेंट जोड़ें


14

मैंने एक DB में एक तालिका बनाई जो पहले से ही किसी अन्य DB में मौजूद है। यह शुरू में पुराने डीबी डेटा से आबाद था। तालिका के PK को उन मानों को प्राप्त करना था जो पहले से ही उन रिकॉर्डों पर मौजूद हैं, इसलिए यह स्वायत्तता नहीं हो सकती है।

अब मुझे अपने पीके को स्वदेशी के रूप में नई तालिका की आवश्यकता है। लेकिन पीके पहले से मौजूद है और डेटा होने के बाद मैं यह कैसे कर सकता हूं?


3
जब आप कहते हैं "संकेत" क्या वास्तव में आप का उल्लेख कर रहे हैं? SQL सर्वर में एक स्तंभ के लिए ऐसी कोई संपत्ति नहीं है। क्या आपका मतलब है IDENTITY?
मैक्स वर्नोन

हाँ, यह कैसे MSSQL में कहा जाता है। सामान्य तौर पर डेटाबेस में, यह एक ऑटोइन्क्रिमेंट पीके है।
Hikari

जवाबों:


14

जिस तरह से मैं आपके प्रश्न को समझ रहा हूं, वह यह है कि आपके पास एक स्तंभ के साथ एक मौजूदा तालिका है जो अब तक मैन्युअल मानों के साथ आबाद है, और अब आप (1) इस स्तंभ को एक IDENTITYस्तंभ बनाना चाहते हैं , और (2) सुनिश्चित करें कि IDENTITYप्रारंभ मौजूदा पंक्तियों में सबसे हाल के मूल्य से।

सबसे पहले, कुछ परीक्षण डेटा के साथ खेलने के लिए:

CREATE TABLE dbo.ident_test (
    id    int NOT NULL,
    xyz   varchar(10) NOT NULL,
    CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id)
);

INSERT INTO dbo.ident_test (id, xyz)
VALUES (1, 'test'),
       (2, 'test'),
       (5, 'test'),
       (6, 'test'),
       (10, 'test'),
       (18, 'test'),
       (19, 'test'),
       (20, 'test');

लक्ष्य तालिका के प्राथमिक कुंजी कॉलम को बनाना है id, एक IDENTITYकॉलम जो अगले रिकॉर्ड के लिए 21 पर शुरू होगा जो सम्मिलित हो जाता है। इस उदाहरण के लिए, स्तंभ xyzतालिका के सभी अन्य स्तंभों का प्रतिनिधित्व करता है।

इससे पहले कि आप कुछ भी करें, कृपया इस पोस्ट के नीचे चेतावनी पढ़ें।

सबसे पहले, अगर कुछ गलत हो जाता है:

BEGIN TRANSACTION;

अब, एक अस्थायी कार्य कॉलम जोड़ते हैं, id_tempऔर उस कॉलम को मौजूदा idकॉलम के मानों पर सेट करते हैं:

ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;

अगला, हमें मौजूदा idकॉलम को ड्रॉप करने की आवश्यकता है (आप मौजूदा कॉलम में सिर्फ "जोड़" नहीं सकते IDENTITY, आपको कॉलम को एक के रूप में बनाना होगा IDENTITY)। प्राथमिक कुंजी को भी जाना है, क्योंकि स्तंभ इस पर निर्भर करता है।

ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;

... और IDENTITYप्राथमिक कुंजी के साथ , इस बार फिर से कॉलम जोड़ें :

ALTER TABLE dbo.ident_test ADD id int IDENTITY(1, 1) NOT NULL;
ALTER TABLE dbo.ident_test ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id);

यहां यह दिलचस्प है। आप IDENTITY_INSERTतालिका पर सक्षम कर सकते हैं , जिसका अर्थ है कि आप मैन्युअल रूप से एक IDENTITYस्तंभ के मूल्यों को परिभाषित कर सकते हैं जब आप नई पंक्तियाँ डाल रहे हैं (मौजूदा पंक्तियों को अपडेट नहीं कर रहे हैं, हालांकि)।

SET IDENTITY_INSERT dbo.ident_test ON;

उस सेट के साथ, DELETEतालिका की सभी पंक्तियाँ, लेकिन आप जिन पंक्तियों को हटा रहे हैं, वे OUTPUTठीक उसी तालिका में हैं - लेकिन idकॉलम के लिए विशिष्ट मानों के साथ (बैकअप कॉलम से)।

DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);

एक बार, किया, IDENTITY_INSERTफिर से बंद कर दें।

SET IDENTITY_INSERT dbo.ident_test OFF;

हमारे द्वारा जोड़े गए अस्थायी कॉलम को छोड़ें:

ALTER TABLE dbo.ident_test DROP COLUMN id_temp;

और अंत में, IDENTITYकॉलम idको फिर से शुरू करें, इसलिए अगले रिकॉर्ड को idकॉलम में उच्चतम मौजूदा संख्या के बाद फिर से शुरू किया जाएगा :

DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)

उदाहरण तालिका की जाँच करते हुए, सबसे अधिक idसंख्या 20 है।

SELECT * FROM dbo.ident_test;

एक और पंक्ति जोड़ें और इसकी नई जाँच करें IDENTITY:

INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;

उदाहरण में, नई पंक्ति होगी id=21। अंत में, यदि आप खुश हैं, तो लेनदेन करें:

COMMIT TRANSACTION;

महत्वपूर्ण

यह एक तुच्छ ऑपरेशन नहीं है, और यह काफी जोखिम भरा है जिसके बारे में आपको जानकारी होनी चाहिए।

  • इसे समर्पित परीक्षण वातावरण में करें। बैकअप लें। :)

  • मुझे BEGIN/COMMIT TRANSACTIONइसका उपयोग करना पसंद है क्योंकि यह अन्य प्रक्रियाओं को तालिका के साथ खिलवाड़ करने से रोकता है जबकि आप इसे बदलने के बीच में हैं, और यह आपको कुछ गलत होने पर वापस सब कुछ रोल करने की संभावना देता है। हालाँकि, कोई अन्य प्रक्रिया जो आपके लेन-देन को करने से पहले आपकी तालिका तक पहुँचने की कोशिश करती है, प्रतीक्षा समाप्त हो जाएगी। यदि आपके पास एक बड़ी मेज है और / या आप उत्पादन के माहौल में हैं, तो यह बहुत बुरा हो सकता है।

  • OUTPUT .. INTOयदि आपकी लक्ष्य तालिका में विदेशी कुंजी बाधाएँ हैं या ऐसी कई अन्य सुविधाएँ हैं, जिन्हें मैं अपने सिर के ऊपर से याद नहीं रख सकता, तो काम नहीं करेगा। आप इसके बजाय डेटा को एक अस्थायी तालिका में बंद कर सकते हैं, और फिर इसे मूल तालिका में वापस सम्मिलित कर सकते हैं। आप विभाजन स्विचिंग का उपयोग करने में सक्षम हो सकते हैं (भले ही आप विभाजन का उपयोग न करें)।

  • इन कथनों को एक-एक करके चलाएं, न कि एक बैच के रूप में या एक संग्रहीत प्रक्रिया में।

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

  • किसी भी को अक्षम करें INSERTऔर DELETEतालिका पर ट्रिगर करें ।

यदि तालिका को फिर से बनाना एक विकल्प है:

यदि टेबल को फिर से बनाना आपके लिए एक विकल्प है, तो सब कुछ बहुत सरल है:

  • खाली तालिका बनाएँ, साथ idएक के रूप में स्तंभ IDENTITY,
  • IDENTITY_INSERT ONतालिका के लिए सेट करें ,
  • तालिका पॉप्युलेट करें,
  • सेट करें IDENTITY_INSERT OFF, और
  • पहचान उजागर की।

महान जवाब, बहुत बहुत धन्यवाद! वास्तव में मेरे मामले में मैं इसे बस सेट कर सकता हूं IDENTITY_INSERT ON, आबाद कर सकता हूं और इसे निष्क्रिय कर सकता हूं । यही मैं करना चाहता था, लेकिन पता नहीं था कि MSSQL ने इसका समर्थन किया है।
हिकारी

5

डेटा स्थानांतरित करने के लिए UPDATE, DELETE या INSERT का उपयोग करने में काफी समय लग सकता है और डेटा और लॉग फाइल / डिस्क दोनों पर संसाधनों (IO) का उपयोग कर सकते हैं। बड़ी तालिका पर काम करते समय संभावित बहुत सारे रिकॉर्ड के साथ लेनदेन लॉग को भरने से बचना संभव है: विभाजन स्विचिंग का उपयोग करके, केवल मेटाडेटा को बदल दिया जाता है।

इसमें कोई डेटा मूवमेंट शामिल नहीं है और इसलिए इसे वास्तव में जल्दी (लगभग तात्कालिक) किया जाता है।

नमूना तालिका

प्रश्न मूल तालिका DDL नहीं दिखाता है। निम्नलिखित डीडीएल का उपयोग इस उत्तर में एक उदाहरण के रूप में किया जाएगा:

CREATE TABLE dbo.idT(
    id int not null
    , uid uniqueidentifier not null
    , name varchar(50)
);
ALTER TABLE dbo.idT ADD CONSTRAINT PK_idT PRIMARY KEY CLUSTERED(id);

इस क्वेरी के साथ 0 से 15 तक के आधा दर्जन डमी रैंडम आईडी जोड़े गए हैं:

WITH ids(n) AS(
    SELECT x1.n+x2.n*4
    FROM (values(0), (3)) as x1(n)
    CROSS JOIN (values(0), (2), (3)) as x2(n)
)
INSERT INTO idt(id, uid, name)
SELECT n, NEWID(), NEWID() 
FROM ids

में उदाहरण डेटा IdT

id  uid                                     name
0   65533096-5007-43EA-88AD-D6776B3B94FA    6A69D4F2-D682-4168-A92F-4CD2E2DBC21D
3   CE87F1ED-BE1A-4F2D-8D62-E1ECA822D35B    AF0524D9-0DBB-41E1-883B-003CB4E4F012
8   34A1DBFD-4F92-4F34-9F04-4CDC824AB15A    02B4BDA4-D515-4262-9031-0BE496AC24CE
11  51606C95-9DE8-4C30-B23B-F915EEA41156    93258103-9C22-4F9C-85CF-712ED0FB3CE6
12  CEC80431-0513-4751-A250-0EB3390DACAB    2DA6B8AF-3EBC-42B3-A76C-028716E24661
15  5037EA83-286F-4EBC-AD7C-E237B570C1FF    095E51E9-8C38-4104-858F-D14AA810A550

के साथ नई तालिका IDENTITY(0, 1)

एकमात्र समस्या आईडी पर संपत्ति idTकी कमी है IDENTITY(0, 1)। एक समान संरचना वाला एक नया टेबल और IDENTITY(0, 1)बनाया गया है:

CREATE TABLE dbo.idT_Switch(
    id int identity(0, 1) not null
    , uid uniqueidentifier not null
    , name varchar(50)
);
ALTER TABLE dbo.idT_Switch ADD CONSTRAINT PK_idT_Switch PRIMARY KEY CLUSTERED(id);

के अलावा IDENTITY(0, 1), idT_Switchके समान है idT

विदेशी कुंजी

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

विभाजन स्विच

idTऔर idT_Switchटेबल एक संगत संरचना है। का उपयोग करने के बजाय DELETE, UPDATEऔर अपने आप से या पर INSERTपंक्तियों को स्थानांतरित करने के लिए बयानों का उपयोग किया जा सकता है:idTidT_SwitchidTALTER TABLE ... SWITCH

ALTER TABLE dbo.idT
SWITCH TO dbo.idT_Switch;

PK_idT(संपूर्ण तालिका) का एकल 'विभाजन' PK_idT_Switch(और इसके विपरीत) में ले जाया जाता है । idTअब 0 पंक्तियाँ हैं और idT_Switch6 पंक्तियाँ हैं।

आप स्रोत और गंतव्य संगतता आवश्यकताओं की पूरी सूची यहां पा सकते हैं:

विभाजन स्विचिंग का उपयोग करके डेटा को कुशलता से स्थानांतरित करना

ध्यान दें कि इसके उपयोग के SWITCHलिए एंटरप्राइज़ संस्करण की आवश्यकता नहीं है, क्योंकि कोई स्पष्ट विभाजन नहीं है। SQL सर्वर 2005 के बाद से एक पार्टीशन रहित टेबल को सिंगल पार्टीशन वाली एक टेबल माना जाता है।

बदलने के idT

idT अब खाली और बेकार है और गिराया जा सकता है:

DROP TABLE idT;

idT_Switchनाम बदला जा सकता है और पुरानी idTतालिका बदल जाएगी :

EXECUTE sys.sp_rename
    @objname = N'dbo.idT_Switch',
    @newname = N'idT', -- note lack of schema prefix
    @objtype = 'OBJECT';

विदेशी कुंजी

विदेशी कुंजियों को फिर से नई idTतालिका में जोड़ा जा सकता है । idTतालिकाओं को स्विच करने के लिए अनुकूल बनाने के लिए पहले से हटाई गई किसी भी चीज़ को फिर से बनाने की आवश्यकता होगी।

reseed

SELECT IDENT_CURRENT( 'dbo.idT');

यह आदेश देता है। 0. टेबल आईडीटी में मैक्स (आईडी) के साथ 6 पंक्तियाँ हैं। 15. डीबीसीसी चेक (तालिका_नाम) को निम्न प्रकार से किया जा सकता है:

DBCC CHECKIDENT ('dbo.idT');

क्योंकि 15 0 से बड़ा है, यह स्वतः ही MAX (id) की तलाश के बिना फिर से शुरू हो जाएगा:

यदि किसी तालिका के लिए वर्तमान पहचान मान पहचान कॉलम में संग्रहीत अधिकतम पहचान मूल्य से कम है, तो पहचान कॉलम में अधिकतम मूल्य का उपयोग करके इसे रीसेट किया जाता है। निम्न प्रकार के 'अपवाद' अनुभाग देखें।

IDENT_CURRENT अब 15 देता है ।

परीक्षण और डेटा जोड़ें

एक साधारण INSERTकथन:

INSERT INTO idT(uid, name) SELECT NEWID(), NEWID();

इस पंक्ति को जोड़ता है:

id  uid                                     name
16  B395D692-5D7B-4DFA-9971-A1497B8357A1    FF210D9E-4027-479C-B5D8-057E77FAF378

idकॉलम अब पहचान का उपयोग कर रहा है और नव डाला मूल्य वास्तव में 16 (15 + 1) है।

अधिक जानकारी

यहां SWITCHतकनीक पर अधिक पृष्ठभूमि के साथ एक संबंधित प्रश्न और उत्तर दिया गया है:

समर्थित नहीं कॉलम पर पहचान संपत्ति क्यों निकाल रहा है



0

सक्षम और अक्षम IDENTITY_INSERT

अगर आपकी टेबल TABLE_A है तो

  1. पहचान स्तंभ के साथ TABLE_A के समान TABLE_B बनाएँ
  2. IDENTITY_INSERT TABLE_B ON सेट करें
  3. TABLE_A से TABLE_B में INSERT
  4. IDENTITY_INSERT TABLE_B ऑफ सेट करें
  5. ड्रॉप टेबल TABLE_A और नाम तालिका B Exec sp_rename 'TABLE_B', 'TABLE_A'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.