如何使用 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 */
我有要求将相同的 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 */