我有几个相关的表,我希望能够在更新引用时复制某些行。
我想复制表1中的一行,以及它与表2和表3中所有相关的行,并且我试图找出一种有效的方式来做到这一点,而无需遍历行。
例如,我有一张桌子:
+----------+---------------+
| BasketId | BasketName |
+----------+---------------+
| 1 | Home Basket |
| 2 | Office Basket |
+----------+---------------+
每个篮子都有水果:
+---------+----------+-----------+
| FruitId | BasketId | FruitName |
+---------+----------+-----------+
| 1 | 1 | Apple |
| 2 | 1 | Orange |
| 3 | 2 | Mango |
| 4 | 2 | Pear |
+---------+----------+-----------+
每个水果都有一些特性:
+------------+---------+--------------+
| PropertyId | FruitId | PropertyText |
+------------+---------+--------------+
| 1 | 2 | Is juicy |
| 2 | 2 | Hard to peel |
| 3 | 1 | Is red |
+------------+---------+--------------+
对于此示例,我的属性特定于单个水果行,这些“苹果”属性并非所有篮子中所有苹果的属性,仅针对该特定篮子中的特定苹果。
我想做的是复制一个篮子。因此,给定购物篮1,我想创建一个新的购物篮,复制其中包含的水果行,并复制指向这些水果的属性。最后,我希望有这样的数据:
+----------+---------------+
| BasketId | BasketName |
+----------+---------------+
| 1 | Home Basket |
| 2 | Office Basket |
| 3 | Friends Basket|
+----------+---------------+
+---------+----------+-----------+
| FruitId | BasketId | FruitName |
+---------+----------+-----------+
| 1 | 1 | Apple |
| 2 | 1 | Orange |
| 3 | 2 | Mango |
| 4 | 2 | Pear |
| 5 | 3 | Apple |
| 6 | 3 | Orange |
+---------+----------+-----------+
+------------+---------+--------------+
| PropertyId | FruitId | PropertyText |
+------------+---------+--------------+
| 1 | 2 | Is juicy |
| 2 | 2 | Hard to peel |
| 3 | 1 | Is red |
| 4 | 6 | Is juicy |
| 5 | 6 | Hard to peel |
| 6 | 5 | Is red |
+------------+---------+--------------+
复制篮子和它的水果非常简单,但是复制水果的属性在我看来会导致遍历行,我希望在TSQL中有更好的解决方案。
有什么想法吗?
您为什么不加入FruitName来获得包含新旧FruitId的表?考虑到将同时添加信息。...这可能不是最佳选择,但您将不会使用任何循环。
INSERT INTO BASKET(BASKETNAME)
VALUES ('COPY BASKET')
DECLARE @iBasketId int
SET @iBasketId = @@SCOPE_IDENTITY;
insert into Fruit (BasketId, FruitName)
select @iBasketId, FruitName
from Fruit
where BasketId = @originalBasket
declare @tabFruit table (originalFruitId int, newFruitId int)
insert into @tabFruit (originalFruitId, newFruitId)
select o.FruitId, n.FruitId
from (SELECT FruitId, FruitName from Fruit where BasketId = @originalBasket) as o
join (SELECT FruitId, FruitName from Fruit where BasketId = @newBasket) as n
on o.FruitName = n.FruitName
insert into Property (FruitId, PropertyText)
select NewFruitId, PropertyText
from Fruit f join @tabFruit t on t.originalFruitId = f.FruitId
((ab)将MERGE
与MERGE
子句一起使用。
[OUTPUT
可以MERGE
,INSERT
和UPDATE
行。在我们的情况下,我们只需要DELETE
。 INSERT
始终为假,因此始终执行1=0
部分。通常,可能还有其他分支,请参阅文档。 NOT MATCHED BY TARGET
通常用于WHEN MATCHED
; UPDATE
通常用于WHEN NOT MATCHED BY SOURCE
,但是我们在这里不需要它们。
DELETE
的这种复杂形式等效于简单的MERGE
,但与简单的INSERT
不同,它的INSERT
子句允许引用我们需要的列。
我将明确写下表的定义。表中的每个主键均为OUTPUT
。我还配置了外键。
购物篮
IDENTITY
水果
CREATE TABLE [dbo].[Baskets](
[BasketId] [int] IDENTITY(1,1) NOT NULL,
[BasketName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Baskets] PRIMARY KEY CLUSTERED
(
[BasketId] ASC
)
属性
CREATE TABLE [dbo].[Fruits](
[FruitId] [int] IDENTITY(1,1) NOT NULL,
[BasketId] [int] NOT NULL,
[FruitName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Fruits] PRIMARY KEY CLUSTERED
(
[FruitId] ASC
)
ALTER TABLE [dbo].[Fruits] WITH CHECK
ADD CONSTRAINT [FK_Fruits_Baskets] FOREIGN KEY([BasketId])
REFERENCES [dbo].[Baskets] ([BasketId])
ALTER TABLE [dbo].[Fruits] CHECK CONSTRAINT [FK_Fruits_Baskets]
复制篮
首先复制CREATE TABLE [dbo].[Properties](
[PropertyId] [int] IDENTITY(1,1) NOT NULL,
[FruitId] [int] NOT NULL,
[PropertyText] [varchar](50) NOT NULL,
CONSTRAINT [PK_Properties] PRIMARY KEY CLUSTERED
(
[PropertyId] ASC
)
ALTER TABLE [dbo].[Properties] WITH CHECK
ADD CONSTRAINT [FK_Properties_Fruits] FOREIGN KEY([FruitId])
REFERENCES [dbo].[Fruits] ([FruitId])
ALTER TABLE [dbo].[Properties] CHECK CONSTRAINT [FK_Properties_Fruits]
表中的一行,然后使用Baskets
获取生成的SCOPE_IDENTITY
。
ID
复制水果
然后使用BEGIN TRANSACTION;
-- Parameter of the procedure. What basket to copy.
DECLARE @VarOldBasketID int = 1;
-- Copy Basket, one row
DECLARE @VarNewBasketID int;
INSERT INTO [dbo].[Baskets] (BasketName)
VALUES ('Friends Basket');
SET @VarNewBasketID = SCOPE_IDENTITY();
复制Fruits
,并记住表变量中新旧ID之间的映射。
MERGE
复制属性
然后使用记住的新旧水果ID之间的映射复制-- Copy Fruits, multiple rows
DECLARE @FruitIDs TABLE (OldFruitID int, NewFruitID int);
MERGE INTO [dbo].[Fruits]
USING
(
SELECT
[FruitId]
,[BasketId]
,[FruitName]
FROM [dbo].[Fruits]
WHERE [BasketId] = @VarOldBasketID
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT
([BasketId]
,[FruitName])
VALUES
(@VarNewBasketID
,Src.[FruitName])
OUTPUT Src.[FruitId] AS OldFruitID, inserted.[FruitId] AS NewFruitID
INTO @FruitIDs(OldFruitID, NewFruitID)
;
。>>
Properties
检查结果,确认代码正确运行后,将回滚更改为提交。
-- Copy Properties, many rows
INSERT INTO [dbo].[Properties] ([FruitId], [PropertyText])
SELECT
F.NewFruitID
,[dbo].[Properties].PropertyText
FROM
[dbo].[Properties]
INNER JOIN @FruitIDs AS F ON F.OldFruitID = [dbo].[Properties].FruitId
;
我和OP有相同的需求:克隆sql服务器表,它们是层次结构的sql服务器表,其中包含彼此的外键。换句话说,克隆具有父子关系的sql server表。