2010-09-15 3 views
2

У меня есть сценарий, где у меня есть родительская таблица, которая имеет отношения «от 1 до многих» с двумя или тремя таблицами. Эти дочерние таблицы снова имеют отношения «от 1 до многих» с большим количеством таблиц и так далее. Это достигает 5-6 уровней иерархии.Дублирование записей эффективно в tsql

Теперь, основываясь на одном значении первичного ключа родительской таблицы, я хочу дублировать всю информацию, связанную с ним в базе данных. Я написал хранимую процедуру, которая использует курсоры и вставляет дочерние строки один за другим и устанавливает новые значения внешнего ключа с каждой вставкой. Но он потребляет некоторое время, потому что количество записей в дочерних таблицах велико.

Есть ли другой эффективный способ сделать это?

ответ

2

В SQL Server 2008:

CREATE TABLE t_parent (id INT NOT NULL PRIMARY KEY IDENTITY, value VARCHAR(100)) 
CREATE TABLE t_child (id INT NOT NULL PRIMARY KEY IDENTITY, parent INT NOT NULL, value VARCHAR(100)) 
CREATE TABLE t_grandchild (id INT NOT NULL PRIMARY KEY IDENTITY, child INT NOT NULL, value VARCHAR(100)) 

INSERT 
INTO t_parent (value) 
VALUES ('Parent 1') 

INSERT 
INTO t_parent (value) 
VALUES ('Parent 2') 

INSERT 
INTO t_child (parent, value) 
VALUES (1, 'Child 2') 

INSERT 
INTO t_child (parent, value) 
VALUES (2, 'Child 2') 

INSERT 
INTO t_grandchild (child, value) 
VALUES (1, 'Grandchild 1') 

INSERT 
INTO t_grandchild (child, value) 
VALUES (1, 'Grandchild 2') 

INSERT 
INTO t_grandchild (child, value) 
VALUES (2, 'Grandchild 3') 

DECLARE @tt TABLE (oid INT, nid INT) 

MERGE 
INTO t_parent 
USING (
     SELECT id, value 
     FROM t_parent 
     ) p 
ON  1 = 0 
WHEN NOT MATCHED THEN 
INSERT (value) 
VALUES (value) 
OUTPUT p.id, INSERTED.id 
INTO @tt; 

MERGE 
INTO t_child 
USING (
     SELECT c.id, p.nid, c.value 
     FROM @tt p 
     JOIN t_child c 
     ON  c.parent = p.oid 
     ) c 
ON  1 = 0 
WHEN NOT MATCHED THEN 
INSERT (parent, value) 
VALUES (nid, value) 
OUTPUT c.id, INSERTED.id 
INTO @tt; 

INSERT 
INTO t_grandchild (child, value) 
SELECT c.nid, gc.value 
FROM @tt c 
JOIN t_grandchild gc 
ON  gc.child = c.oid 

В более ранних версиях SQL Server, вам придется сделать SELECT, за которым следует INSERT, чтобы узнать новые значения PRIMARY KEY.

+0

Спасибо Quassnoi, я использую SQL 05. Можете ли вы PLZ привести пример использования OUTPUT в INSERT. Я хочу добавить новые идентификаторы записей. – Sami

1

Вам нужно будет вставить одну таблицу за раз, но вы можете сделать это, вставив наборы вместо строк, если вы допустили значения FK в дочерних таблицах нового родителя так же, как значения FK оригинала родитель.

Скажите, что у вас есть представление о вашей родительской таблице, и в вашем sp вы ограничиваете ее копией строки (pk = 1, скажем). Затем вставьте эту строку в родительскую таблицу, заменяя PK = 2 для PK val.

Теперь используйте второй вид одной из дочерних таблиц. В вашем sp ограничьте набор строк теми, у кого есть PK = 1. Снова вставьте все эти строки в ту же дочернюю таблицу, заменяющую PK = 2 для поля PK.

Смежные вопросы