从CSV导入多行至SQL Server时生成唯一Num Contrat的问题
解决SQL Server主键重复问题的排查步骤
可能的原因及修复方案
1. 计数器未按原Num Contrat分组
如果脚本使用全局计数器(整个CSV只维护一个递增变量),而非为每个重复的原Num Contrat单独维护计数器,会导致不同原编号生成的新编号重复。比如原编号CONTRAT-001和CONTRAT-101的后两位都是01,全局计数器会让两者的后缀序列重叠,最终生成重复的新编号。
修复:
用哈希表按原Num Contrat分组管理计数器:
# 初始化哈希表存储每个原编号的当前计数器 $counterTable = @{} foreach ($row in $csvData) { $originalNum = $row.'Num Contrat' # 首次处理该原编号时,初始化计数器为1 if (-not $counterTable.ContainsKey($originalNum)) { $counterTable[$originalNum] = 1 } # 生成两位格式的后缀(自动补零) $suffix = $counterTable[$originalNum].ToString("D2") # 生成新编号:原编号拼接后缀(可按需添加分隔符) $newNumContrat = "{0}-{1}" -f $originalNum, $suffix # 递增当前原编号的计数器 $counterTable[$originalNum]++ # 后续导入SQL的逻辑... }
这样每个原编号的后缀独立递增,不会和其他原编号的序列冲突。
2. 新编号仅依赖原编号后两位
如果新编号是原编号后两位 + 后缀,而非完整原编号 + 后缀,只要两个不同原编号的后两位相同,就会生成重复的新编号(比如0101可能来自多个原编号)。
修复:
基于完整原编号生成新编号,示例:
# 直接拼接原编号与后缀 $newNumContrat = "{0}{1}" -f $originalNum, $suffix # 或用分隔符区分原编号与后缀,避免格式混淆 $newNumContrat = "{0}-{1}" -f $originalNum, $suffix
3. 未处理数据库中已存在的编号
即使脚本生成的新编号在CSV内唯一,也可能和SQL Server中已有的主键重复。
修复:
导入前先查询数据库中已有的编号,生成新编号时检查是否重复:
# 从SQL查询现有编号并存入哈希集合(查询逻辑需自行实现) $existingNums = Invoke-SqlCmd -ServerInstance "YourServer" -Database "YourDB" -Query "SELECT [Num Contrat] FROM Contrats" | Select-Object -ExpandProperty "Num Contrat" $existingSet = [System.Collections.Generic.HashSet[string]]::new($existingNums) foreach ($row in $csvData) { $originalNum = $row.'Num Contrat' if (-not $counterTable.ContainsKey($originalNum)) { $counterTable[$originalNum] = 1 } # 循环生成直到找到未存在的编号 do { $suffix = $counterTable[$originalNum].ToString("D2") $newNumContrat = "{0}-{1}" -f $originalNum, $suffix $counterTable[$originalNum]++ } while ($existingSet.Contains($newNumContrat)) # 将新编号加入集合,避免当前批次内重复 $existingSet.Add($newNumContrat) | Out-Null # 导入SQL... }
4. 并发或事务问题
若脚本采用多线程处理,可能出现同时生成相同编号的情况;未使用事务的话,部分导入失败会导致后续编号混乱。
修复:
- 采用单线程处理CSV数据,避免并发生成编号;
- 导入时使用SQL事务,若出现主键冲突则回滚并重试(或调整编号后重试)。
调试建议
- 生成新编号后先输出到日志,检查是否有重复:
$newNums = @() foreach ($row in $csvData) { # 生成新编号逻辑... $newNums += $newNumContrat } # 检测重复项 $duplicates = $newNums | Group-Object | Where-Object { $_.Count -gt 1 } if ($duplicates) { Write-Warning "发现重复编号:$($duplicates.Name -join ', ')" }
- 查看SQL Server的主键冲突错误日志,定位具体重复的编号,反向排查生成逻辑问题。
内容的提问来源于stack exchange,提问作者GeffGeff
相关产品推荐
相关产品推荐

