如何按条件从源表向多张目标表插入数据
数据批量插入方案
需求概述
从源表向指定目标表插入数据,需满足:
- 严格按照参数表定义的行数插入,无重复数据
- 同批次(相同
FILENAME)下,按ID顺序划分源表数据行范围:先取前N行插入第一个目标表,再接着取M行插入下一个目标表(如FILENAME_X批次,前200行入TABLE_A,第201-500行入TABLE_B)
数据表结构
参数表(dbo.parameter_table)
| ID | 批次文件名 | 总数据行数 | 待插入行数 | 目标表 |
|---|---|---|---|---|
| 1 | FILENAME_X | 500 | 200 | TABLE_A |
| 2 | FILENAME_X | 500 | 300 | TABLE_B |
| 3 | FILENAME_Y | 400 | 100 | TABLE_C |
| 4 | FILENAME_Y | 400 | 300 | TABLE_D |
源表
| 源表ID(s_id) | 手机号 | 姓名 |
|---|---|---|
| 78 | Cell 1 | Cell 2 |
| 88 | Cell 3 | Cell 4 |
目标表(TABLE_A/TABLE_B/TABLE_C/TABLE_D,结构完全一致)
| ID | 手机号 | 姓名 |
|---|---|---|
| 1 | XXXX | XXXX |
| 2 | XXXX | XXXX |
| 3 | XXXX | XXXX |
| 4 | XXXX | XXXX |
修正后的SQL实现代码
原代码存在变量重复赋值、游标未声明、无批次行号跟踪等问题,以下是完善版本:
-- 声明变量 DECLARE @RowNum INT, @ID INT, @FILENAME VARCHAR(100), @TOTAL_ROWS INT, @NUMBER_OF_ROWS_TO_INSERT INT, @DESTINATION_TABLE VARCHAR(100), @CurrentStartRow INT = 1 -- 跟踪当前批次的起始行号 -- 声明游标:按批次分组,同批次内按ID排序确保插入顺序正确 DECLARE cursor_files CURSOR FOR SELECT ROW_NUMBER() OVER(PARTITION BY FILENAME ORDER BY ID) AS RowNum, ID, FILENAME, TOTAL_ROWS, NUMBER_OF_ROWS_TO_INSERT, DESTINATION_TABLE FROM [dbo].[parameter_table] ORDER BY FILENAME, ID OPEN cursor_files -- 首次读取游标数据 FETCH NEXT FROM cursor_files INTO @RowNum, @ID, @FILENAME, @TOTAL_ROWS, @NUMBER_OF_ROWS_TO_INSERT, @DESTINATION_TABLE WHILE @@FETCH_STATUS = 0 BEGIN IF @NUMBER_OF_ROWS_TO_INSERT > 0 BEGIN -- 动态构建插入语句,按行范围筛选源表数据 DECLARE @InsertSQL NVARCHAR(MAX) SET @InsertSQL = N' INSERT INTO ' + QUOTENAME(@DESTINATION_TABLE) + ' (ID, PHONE, NAME) SELECT s_id, PHONE, NAME FROM ( -- 对源表数据生成连续行号,确保行范围稳定(可根据实际需求调整排序字段) SELECT s_id, PHONE, NAME, ROW_NUMBER() OVER(ORDER BY s_id) AS SourceRowNum FROM [dbo].[source_table] -- 替换为你的实际源表名称 ) t WHERE SourceRowNum BETWEEN ' + CAST(@CurrentStartRow AS NVARCHAR(10)) + ' AND ' + CAST(@CurrentStartRow + @NUMBER_OF_ROWS_TO_INSERT - 1 AS NVARCHAR(10)) -- 执行动态SQL EXEC sp_executesql @InsertSQL -- 更新下一次插入的起始行号 SET @CurrentStartRow = @CurrentStartRow + @NUMBER_OF_ROWS_TO_INSERT END -- 检查下一条数据是否属于新批次,若是则重置起始行号 DECLARE @NextFilename VARCHAR(100) FETCH NEXT FROM cursor_files INTO @RowNum, @ID, @NextFilename, @TOTAL_ROWS, @NUMBER_OF_ROWS_TO_INSERT, @DESTINATION_TABLE IF @@FETCH_STATUS = 0 BEGIN IF @NextFilename <> @FILENAME BEGIN SET @CurrentStartRow = 1 -- 回退游标,确保下一次循环处理当前读取的新批次数据 FETCH PRIOR FROM cursor_files INTO @RowNum, @ID, @FILENAME, @TOTAL_ROWS, @NUMBER_OF_ROWS_TO_INSERT, @DESTINATION_TABLE END ELSE BEGIN -- 回退游标,继续处理当前批次 FETCH PRIOR FROM cursor_files INTO @RowNum, @ID, @FILENAME, @TOTAL_ROWS, @NUMBER_OF_ROWS_TO_INSERT, @DESTINATION_TABLE END END -- 读取下一条游标数据 FETCH NEXT FROM cursor_files INTO @RowNum, @ID, @FILENAME, @TOTAL_ROWS, @NUMBER_OF_ROWS_TO_INSERT, @DESTINATION_TABLE END -- 清理游标 CLOSE cursor_files DEALLOCATE cursor_files
关键实现说明
- 批次行号跟踪:用
@CurrentStartRow变量记录当前批次的起始行,避免跨批次行号混乱,确保同批次内数据连续无重复 - 动态SQL适配:通过
QUOTENAME函数防止SQL注入,同时适配不同目标表 - 游标分组排序:用
PARTITION BY FILENAME对批次分组,同批次内按ID排序,保证插入顺序符合需求 - 源表行号稳定:对源表数据生成连续行号(按
s_id排序),确保每次执行的行范围一致
内容的提问来源于stack exchange,提问作者BΛDЯ
相关产品推荐
相关产品推荐

