SQL Server如何将表行按Qty字段批量复制为多行至另一表?
解决SQL Server存储过程重复插入、行数翻倍问题
正确的存储过程实现(替代循环的高效方案)
避免使用逐行循环(易引发逻辑错误或并发问题),改用递归CTE生成对应次数的行,直接批量插入:
CREATE PROCEDURE crdShuffleDeck AS BEGIN SET NOCOUNT ON; -- 生成唯一的新RoundID,加锁避免并发冲突 DECLARE @NewRoundID INT; BEGIN TRANSACTION; SELECT @NewRoundID = ISNULL(MAX(RoundID), 0) + 1 FROM crdShuffle WITH (UPDLOCK, HOLDLOCK); -- 递归CTE生成1到最大Qty的数字序列 WITH NumberSequence AS ( SELECT 1 AS Num UNION ALL SELECT Num + 1 FROM NumberSequence WHERE Num < (SELECT MAX(Qty) FROM crdCard) ) -- 批量插入对应次数的行到crdShuffle INSERT INTO crdShuffle (RoundID, CardID, /* 替换为你的实际字段 */) SELECT @NewRoundID, c.CardID, -- 这里添加crdCard中需要复制的其他字段 c.CardName, c.CardType -- 示例字段,根据实际表结构调整 FROM crdCard c JOIN NumberSequence ns ON ns.Num <= c.Qty OPTION (MAXRECURSION 0); -- 当最大Qty超过100时必须开启 COMMIT TRANSACTION; END
导致重复插入的常见原因
- 存储过程被重复调用:应用端重复发起请求、作业配置重复执行,或触发器触发多次,导致同一批数据被插入多次。
- RoundID生成无锁保护:并发场景下多个会话同时获取到相同的RoundID,造成同一RoundID下重复插入数据。
- 原循环逻辑错误:逐行循环时,内层循环次数计算错误、变量未正确重置,或循环条件导致重复遍历行。
- 事务处理不当:未正确提交/回滚事务,导致重试时重复插入数据。
排查与修复步骤
- 验证调用频次:检查应用日志、SQL Server作业历史,确认
crdShuffleDeck是否被多次执行。 - 修复RoundID生成逻辑:必须加
UPDLOCK, HOLDLOCK锁,确保并发时RoundID唯一,避免冲突。 - 替换循环为批量插入:递归CTE的批量插入方式比逐行循环更高效,且避免循环逻辑错误。
- 检查表结构与数据:确认
crdCard表的Qty字段值是否正确,是否存在异常大值导致插入行数超出预期。 - 查看插入时间戳:如果
crdShuffle表有创建时间字段,查询重复行的插入时间,判断是单次执行插入多次还是多次执行存储过程。
内容的提问来源于stack exchange,提问作者user3666570
相关产品推荐
相关产品推荐

