如何使用 MS SQL CTE 在同一个 table 中将记录从 parent 复制到 child

How to copy records from parent to child in same table using MS SQL CTE

我有要求将相同的 parent 记录复制到 N child 和相同的 table。 数据的唯一区别是 Parent Id 和客户端 Id,我必须将 Parent 记录原样复制到 child,只有 ParentId 和 ClientId 值改变。 - Parent 记录可能是 1 到 2000,需要为每个客户移动。 - Child 记录(重复 1 到 1000)不同 child。

我已经使用 SQL 服务器游标实现了要求,但是如果我们有 parent 记录超过 1000 条并且 Child(重复条目)超过 1500 条,这将非常缓慢。所以我想知道是否可以使用 CTE 而不是游标来获得批量插入的性能。

我正在使用以下代码将 parent 条记录复制到每个客户端:

DECLARE @id bigint;
--Get list of client which will repeat the rows from Master entries
--This will return three rows Id:1,5,7
DECLARE client_cursor CURSOR FOR SELECT Id FROM Client WHERE ClientName like 'info%' 
OPEN client_cursor
    FETCH NEXT FROM client_cursor INTO @id;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        /*....*/
        /* Other business logic performed here */
        /*....*/
        INSERT INTO Resources (ParentId,ClientId,Location,Title,[Status],Alert)
        --This will return two rows Id:1,2
        SELECT Id,@id,Location,Title,[Status],Alert FROM Resources WHERE ParentId IS NULL AND ClientId IS NULL  

        FETCH NEXT FROM client_cursor INTO @id
    END 
CLOSE client_cursor;
DEALLOCATE client_cursor;

以下是使用上述代码片段将批量 Parent 记录添加到 Child 之前和之后的屏幕截图。

-- Table Creation
CREATE TABLE [dbo].[Client](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [ClientName] [varchar](50) NULL,
 CONSTRAINT [PK_Client] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Resources](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [ParentId] [bigint] NULL,
    [ClientId] [bigint] NULL,
    [Location] [varchar](50) NULL,
    [Title] [varchar](50) NULL,
    [Status] [varchar](50) NULL,
    [Alert] [varchar](50) NULL,
 CONSTRAINT [PK_Resources] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

-- Default Data Insertion
SET IDENTITY_INSERT [dbo].[Client] ON 
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (1, N'Infosstretch')
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (2, N'Microsoft')
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (3, N'Sun System')
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (4, N'IBM')
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (5, N'Infosys')
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (6, N'TCS')
INSERT [dbo].[Client] ([Id], [ClientName]) VALUES (7, N'Infomatica')
SET IDENTITY_INSERT [dbo].[Client] OFF

SET IDENTITY_INSERT [dbo].[Resources] ON 
INSERT [dbo].[Resources] ([Id], [ParentId], [ClientId], [Location], [Title], [Status], [Alert]) VALUES (1, NULL, NULL, N'India', N'Master A', N'New', N'Issue with location')
INSERT [dbo].[Resources] ([Id], [ParentId], [ClientId], [Location], [Title], [Status], [Alert]) VALUES (2, NULL, NULL, N'Australia', N'Master B', N'Updated', N'No major issue')
SET IDENTITY_INSERT [dbo].[Resources] OFF

为了简洁起见,您的业务规则中可能有一些原因已在此处删除,但为什么不这样呢?

INSERT #Resources
SELECT
    R.Id AS ParentId,
    C.Id AS ClientId,
    R.Location,
    R.Title,
    R.Status,
    R.Alert
FROM #Resources R
    CROSS JOIN #Client C
WHERE R.ParentId IS NULL AND R.ClientId IS NULL -- Root level
    AND NOT EXISTS (SELECT * FROM #Resources WHERE ParentId = R.Id) -- Not already populated
    -- AND /* Other business logic performed here */