2010-05-13 83 views
9

代表的樹形結構鑑於代表樹狀層次結構有三列使用SQL克隆數據庫中

  1. ID表(主鍵,未自增)
  2. ParentGroupID
  3. someValue中

我知道該分支的最低節點,我想將它複製到具有相同數量父母的新分支,這些分支也需要克隆。

我正在嘗試編寫一個SQL INSERT INTO語句,該語句將使每個具有相同主體的行的副本具有第一部分GroupID到新的GroupID中。

實例開始表:

ID | ParentGroupID | SomeValue 
------------------------ 
1 |  -1  | a 
2 |  1  | b 
3 |  2  | c 

目標我運行一個簡單的INSERT INTO語句後:

ID | ParentGroupID | SomeValue 
------------------------ 
1 |  -1  | a 
2 |  1  | b 
3 |  2  | c 
4 |  -1  | a-cloned 
5 |  4  | b-cloned 
6 |  5  | c-cloned 

最終的樹結構

+--a (1) 
| +--b (2) 
|  +--c (3) 
| 
+--a-cloned (4) 
| +--b-cloned (5) 
|  +--c-cloned (6) 

ID是不總是很好地隔開因爲這個演示數據顯示,所以我不能總是假定父母的ID比1小1具有父母的行的當前ID。

此外,我正在嘗試在T-SQL(對於Microsoft SQL Server 2005及更高版本)中執行此操作。

這聽起來像一個經典的練習,應該有一個純SQL答案,但我太習慣編程了,我的思想在關係型SQL中並不認爲。

+3

您正在使用哪種版本的SQL Server? – 2010-05-13 20:46:53

+0

我不清楚克隆的ParentGroupID是如何確定的。 B的克隆是如何獲得ParentGroupId爲4的,而A的克隆的ParentGroupId是否等於它的源行? – Thomas 2010-05-13 20:55:29

+0

我需要支持SQL Server 2005.(我更新了原始帖子以表明這一點) – AmoebaMan17 2010-05-13 21:02:51

回答

3

試試這個,根據從查詢Quassnoi的文章Adjacency List vs Nested Sets: SQL Server

WITH q AS 
(
    SELECT h.*, 1 AS level 
    FROM Table1 h 
    WHERE id = 3 
    UNION ALL 
    SELECT hp.*, level + 1 
    FROM q 
    JOIN Table1 hp 
    ON  hp.id = q.ParentGroupID 
), q2 AS (
    SELECT 
     ID, 
     ParentGroupID, 
     SomeValue, 
     (SELECT MAX(level) FROM q) - level AS level 
    FROM q 
) 
INSERT INTO table1 
SELECT 
    (SELECT MAX(ID) FROM Table1) + level + 1 AS ID, 
    CASE WHEN level = 0 THEN -1 
     ELSE (SELECT MAX(ID) FROM Table1) + level 
    END AS ParentGroupID, 
    SomeValue + '-cloned' 
FROM q2 

結果,當您的測試數據上運行:

ID ParentGroupID SomeValue 
1 -1    a   
2 1    b   
3 2    c   
4 -1    a-cloned 
5 4    b-cloned 
6 5    c-cloned 
+0

我要試一試!再次感謝Mark!我需要開始趕上你和Quassnoi的帖子,因爲你們總是有一個答案! – AmoebaMan17 2010-05-13 21:11:25

2

Assming該ID是標識列,具有自動分配的值。 我正在做這個袖口,所以任何語法錯誤appologies。我希望評論意圖清楚。

/* Find all ancestors for a given ID */ 
WITH Ancestors(ChildID, AncestorID) AS 
(
    SELECT id AS ChildID, id As AncestorID 
    FROM YourTable WHERE ParentGroupID=--1 
    UNION ALL 
    SELECT a.ChildID, d.ParentGroupID 
    FROM Ancestors AS a INNER JOIN 
     YourTable d ON d.ID = a.AncestorID 
    WHERE (b1.ParentGroupID <> -1)) 
), 
/* Insert new rows for all ancestors of a given ID and save the results, so we have access to the new ID. we also have a column for the old ID. */ 
IDMap(ID, ParentGroupID, SomeValue, OldID) AS 
{ 
    // insert, using identity column assigned ID, and save the old ID 
    INSERT INTO YourTable SELECT d.ParentGroupID, d.SomeValue+"-cloned", d.ID FROM YourTable d 
     INNER JOIN Ancestors a ON a.ChildID = d.ID 
     WHERE a.AncestorID=<the ID to clone> 
} 
/* Now update the parentID in the inserted data to the new ID */ 
UPDATE YourTable 
SET ParentGroupID = map.ID 
FROM YouTable t INNER JOIN (SELECT * FROM IDMap) map 
    ON t.ParentGroupID=map.OldID 
+0

我沒有看到任何對'@@ identity'的調用,你在哪裏得到它 – Omu 2010-05-19 12:21:02

+0

我同意,我也沒有看到它。我期待在IDMap CTE上有一個OUTPUT子句。也許它會被深夜的大霧所扼殺。我會更新查詢。 – mdma 2010-05-19 19:48:50