2011-07-18 31 views
3

我在這裏發現此線程:http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=16836 我有完全相同的問題。報價:sql中行的級聯副本

羅布紅蘋果寫道:「我有一個持有疑問3個表

表1:問題

字段:ID(唯一的)字段:姓名(文本)

表2:問題文本(參考表1-ID)

字段:ID(唯一)字段:QuestionID(inte GER裁判表1 ID) 字段:文本

表3:選項

字段:ID(唯一)字段:QuestionTextID(整數裁判表2 ID) 字段:文本

說,例如,我用2個問題文本記錄和選項記錄創建了一個問題。如果我想將該問題複製到新的 問題中,並將問題文本記錄複製到新ID和所有 相關選項,我怎樣才能輕鬆完成此任務(因爲重複的 問題將有一個新的ID,每個。中複製的問題文本的 將有新的ID,這將每個選項)」

建議的解決方案是:

create procedure CopyQuestion 
@idtocopy int 
AS 
declare @tempquestionid 
declare @tempquestiontextid 
declare @questiontextid 

insert into question (name) 
    select name from question where id = @idtocopy 

select @tempquestionid = @@identity 

declare question_cursor cursor for 
    select id from [question text] where id = @idtocopy 
open question_cursor 
fetch next from question_cursor into @questiontextid 
while @@fetch_status = 0 
begin 
    insert into [question text] (questionid, text) 
     select @tempquestionid, text from [question text] where id = @questiontextid 
    select @tempquestiontextid = @@identity 
     insert into [options] (questiontextid, text) 
    select @tempquestiontextid, text from [options] where questiontextid = @questiontextid 
    fetch next from question_cursor into @questiontextid 
end 
close question_cursor 
deallocate question_cursor 

是否有更好的解決這個問題,我將使用插入觸發器 謝謝!

+1

我還沒有仔細查看其餘的邏輯,但請停止使用@@ IDENTITY - 使用SCOPE_IDENTITY()代替。所以問題有id和name,你可以使用完全相同的名稱創建一個新的問題,但新的代理標識值?用戶將如何區分他們 - 他們是否必須記住ID? –

+0

我會的。我更關心光標,並且我認爲有更好的方法去做 – user194076

+0

不理解邏輯。如果遊標實際上說WHERE questionid = @idtocopy?你似乎在混合使用一個名爲「ID」的列......這個光標實際上是做你期望的嗎?你能展示一些樣本數據和期望的結果嗎?另外,你的數據類型真的是TEXT?您應該在SQL Server 2008中使用VARCHAR或NVARCHAR。TEXT已棄用。 –

回答

4

可以使用merge語句輸出子句,以獲得新老ID在questionText之間的匹配。這在這個問題Using merge..output to get mapping between source.id and target.id中描述。

在你的情況下,代碼看起來像這樣。該代碼未經過測試,因此可能會有任何數量的拼寫錯誤,但它顯示了您可以執行的操作。

create procedure CopyQuestion 
    @idtocopy int 
as 

declare @QuestionID int 

insert into question 
select Name 
from question 
where ID = @idtocopy 

select @QuestionID = scope_identity() 

declare @IDs table (NewQID int, OldQID int) 

merge questionText as T 
using (select ID, @QuestionID as QuestionID, Field 
     from questionText 
     where QuestionID = @idtocopy) as S 
on 0=1 
when not matched then 
    insert (QuestionID, Field) values (QuestionID, Field) 
output inserted.ID, S.ID into @IDs;  

insert into options 
select 
    I.NewQID, 
    O.Field 
from options O 
    inner join @IDs as I 
    on O.QuestionTextID = I.OldQID 
+0

+1。這似乎是SQL Server 2008的最佳答案。 – rsbarro

0

這是另一種方法來做同樣的事情更多一點基礎。在我的下面的例子中,我使用了一個臨時表來映射兩個新表之間的ID。另外,請刪除表名中的空格(僅僅因爲你可以不意味着你應該)。

CREATE PROCEDURE udf_COPY_QUESTION 
@ID_TO_COPY int 
as 
BEGIN TRANSACTION 
BEGIN TRY 
DECLARE @NEW_QUESTION_ID INT, @MAX_ID INT 
insert into question (name) 
    select name from question where id = @ID_TO_COPY 
SET @NEW_QUESTION_ID = SCOPE_IDENTITY() 
SET @MAX_ID =IDENT_CURRENT('question text') 
select @NEW_QUESTION_ID AS questionid, 
     Text, 
     ROW_NUMBER() OVER (ORDER NAME) + @MAX_ID as new_text_id, 
     id as old_text_id 
INTO #TEMP from [question text] 
     where questionid = @ID_TO_COPY   
insert into [question text] (QuestionID,Text) 
     select questionid,Text from #TEMP 
     order by new_text_id 
insert into Options (questiontextid, text) 
     select t.new_text_id,o.Text from options o 
     inner join #temp t on t.old_text_id = o.questiontextid 
COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    RAISERROR('COPY FAILED',10,1) 
    ROLLBACK TRANSACTION 
END CATCH  
+0

整潔的方法,但如果你不把整個事情包裝在一個事務中,它可能會失敗。如果其他用戶在運行時嘗試複製或添加問題,則ID可能不同步。 – rsbarro

+0

也可能有點危險,假設QuestionText.ID值是按順序發出的(無論如何)。這就是爲什麼我認爲光標可能是解決這個問題的最好方法的原因之一。 – rsbarro

+0

我也想到了這一點,但如果唯一的領域是問題的文本是否選項與text1或text2包含相同的文本配對最終的結果是完全相同的。我同意交易方面。對於MERGE,爲 – JStead