2010-10-04 11 views
5

मेरे डेटाबेस इस तरह दिखता है:टी-एसक्यूएल: पदानुक्रम डेटा की प्रतिलिपि बनाने का सबसे अच्छा तरीका?

Questionnaire 
Id 
Description 

Category 
id 
description 
QuestionnaireId (FK)  

Question 
id 
CategoryId (FK) 
field 

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

मैं टी-एसक्यूएल का उपयोग करके यह कैसे कर सकता हूं?

+3

मैं वास्तव में यहाँ समस्या का हल नहीं ... बस डेटा की प्रतिलिपि और 'सेट identity_insert [तालिका एक] ON' B & सी – Jamiec

+0

के लिए एक ही का उपयोग कर सम्मिलित न अगर मैं तालिका ए में एक रिकॉर्ड डालें, इस रिकॉर्ड को एक आईडी मिलती है, मान लें 104. इससे पहले, मुझे तालिका बी में एक नई पंक्ति डालना है, जिसमें tableA का संदर्भ है, इसलिए table_A_id समान होना चाहिए: 104 – Martijn

+1

नहीं होना चाहिए जब तक आप कॉपी कर रहे हों, तब तक एक समस्या खाली है, क्योंकि नए डेटा में समान PK का IDENTITY_INSERT का उपयोग किया जाएगा। आप कहां कॉपी करने की कोशिश कर रहे हैं? शायद एक और समान डेटाबेस? – Jamiec

उत्तर

5

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

DECLARE @newQuestionnaireId INT 
    INSERT INTO Questionnaire 
    (Id,Description) 
    SELECT Id, Description 
    FROM Questionnaire 
    WHERE ID = @sourceQuestionnaireID 
    SET @newquestionnaireId = SCOPE_IDENTITY() 

इस बिंदु पर आपके पास एक नया हेडर रिकॉर्ड है, और प्रतिलिपि के लिए नव निर्मित आईडी है। अगले कदम के लिए जो नई आईडी

DECLARE @tempCategories TABLE (id INT, description VARCHAR(50),newId INT) 
INSERT INTO @tempCategories(id,description) 
SELECT id, description FROM Category 
WHERE questionnaireId = @sourceQuestionnaireId 

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

DECLARE cuCategory CURSOR FOR SELECT Id, Description FROM @tempCategories 
DECLARE @catId INT, @catDescription, @newCatId INT 
OPEN cuCategory 
FETCH NEXT FROM cuCategory INTO @catId,@catDescription 
WHILE @@FETCH_STATUS<>0 
BEGIN 
    INSERT INTO Category(description,questionnaireId) 
    VALUES(@catDescription,@newQuestionnaireId) 
    SET @newCatId = SCOPE_IDENTITY() 

    UPDATE @tempCategories SET [email protected] 
    WHERE [email protected] 
    FETCH NEXT FROM cuCategory INTO @catId,@catDescription 
END 
CLOSE cuCategory 
DEALLOCATE cuCategory 

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

अंत में, मैं सुझाव दूंगा कि यह पूरा ऑपरेशन लेनदेन के भीतर किया जाता है ताकि आपको कुछ गलत होने पर आधे पूर्ण प्रतियों से बचाया जा सके।

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

संपादित करें: documentation for Cursor operations can be foundhere

+0

धन्यवाद। यह वास्तव में मुझे चाहिए। मैं बहुत सी नई चीजें देखता हूं जिनके साथ मैंने कभी काम नहीं किया है: कर्सर, फ़ेचक्वेटस से आगे निकलें। क्या आप इन चीजों को थोड़ा सा समझा सकते हैं? – Martijn

+3

मैंने व्यावहारिक रूप से आपके लिए उत्तर लिखा है और आप Google में उन कुछ वाक्यांशों को टाइप नहीं कर सकते हैं? शीश। – Jamiec

+0

मुझे लगता है कि मुझे यह मिल गया :) Thnx! – Martijn

2

मैं इस तरह एक समस्या थी और समाधान @Jamiec ने सुझाव दिया को लागू करने के लिए शुरू किया, लेकिन मैं जल्दी से पता चला है कि मैं एक बेहतर समाधान की जरूरत है क्योंकि मेरे मॉडल उदाहरण यहाँ उद्धृत की तुलना में बहुत बड़ा है । मेरे पास तीन इंटरमीडिएट टेबल वाली एक मास्टर टेबल है, जिनमें से प्रत्येक में एक या अधिक तृतीयक सारणी हैं। और तीन मध्यवर्ती प्रत्येक के पास 50 कॉलम की तरह कुछ था। इसका मतलब यह होगा कि यह सब कुछ टाइप करने के लिए, विशेष रूप से अस्थायी memvars के साथ लाने के हिस्से में। मैंने सीधे टेम्पलेट टेबल में फ़ेच करने का कोई तरीका खोजने का प्रयास किया लेकिन ऐसा लगता है कि आप ऐसा नहीं कर सकते हैं। मैंने जो किया वह मूल आईडी नामक मध्यवर्ती तालिकाओं में एक कॉलम जोड़ना था। यहाँ मेरी कोड प्रश्नकर्ता द्वारा प्रयोग किया जाता मॉडल में अनुवाद किया है:

DECLARE @newQuestionnaireId INT 
INSERT INTO Questionnaire (Id,Description) 
SELECT Id, Description FROM Questionnaire 
WHERE ID = @sourceQuestionnaireID 
SET @newquestionnaireId = SCOPE_IDENTITY() 

INSERT INTO Category(QuestionnaireId, description, originalId) 
SELECT @newquestionnaireId, description, id FROM Category 
WHERE questionnaireId = @sourceQuestionnaireId 

INSERT INTO Question SELECT Category.Id, Question.Field 
FROM Question join Category on Question.CategoryId = Category.OriginalId 
WHERE Category.QuestionnaireId = @newquestionnaireId 

अपने मॉडल में आईडी क्षेत्रों सभी पहचान ताकि आप उन्हें आवेषण में आपूर्ति नहीं करते हैं।

एक और बात इससे पहले कि मैं कर्सर दृष्टिकोण पर छोड़ दिया मुझे पता चला this clever little trick था एक को तोड़ने के साथ एक अनंत जबकि पाश का उपयोग करके दो बार बयान FETCH टाइप करने के लिए होने से बचाने के:

1
यहाँ

एक तरह से कर्सर नहीं है कि है , यह घटनाओं के क्रम को याद रखने पर निर्भर करता है, और उसके बाद बच्चों को हल करने के लिए इसका उपयोग करता है।

Declare @Parrent TABLE(ID int PRIMARY KEY IDENTITY, Value nvarchar(50)) 
Declare @Child TABLE(ID int PRIMARY KEY IDENTITY, ParrentID int, Value nvarchar(50)) 

insert into @Parrent (Value) Values ('foo'),('bar'),('bob') 
insert into @Child (ParrentID, Value) Values (1,'foo-1'),(1,'foo-2'),(2,'bar-1'),(2,'bar-2'),(3,'bob') 

declare @parrentToCopy table (ID int) -- you can me this a collection 
insert into @parrentToCopy values (2) 

select * from @Parrent p inner join @Child c on p.ID = c.ParrentID order by p.ID asc, c.ID asc 

DECLARE @Ids TABLE(nID INT); 

INSERT INTO @Parrent (Value) 
OUTPUT INSERTED.ID 
INTO @Ids 
SELECT 
     Value 
FROM @Parrent p 
inner join @parrentToCopy pc on pc.ID=p.ID 
ORDER BY p.ID ASC 

INSERT INTO @Child (ParrentID, Value) 
SELECT 
     nID 
     ,Value 
FROM @Child c 
inner join (select ID, ROW_NUMBER() OVER (ORDER BY ID ASC) AS 'RowNumber' from @parrentToCopy) o ON o.ID = c.ParrentID 
inner join (select nID, ROW_NUMBER() OVER (ORDER BY nID ASC) AS 'RowNumber' from @Ids) n ON o.RowNumber = n.RowNumber 

select * from @Parrent p inner join @Child c on p.ID = c.ParrentID order by p.ID asc, c.ID asc 

पूर्ण पोस्ट यहाँ है http://bashamer.wordpress.com/2011/10/04/copying-hierarchical-data-in-sql-server/

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

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