PowerShell调用Invoke-Sqlcmd批量导入CSV至SQL时遇未闭合引号错误
解决CSV批量导入SQL Server时的引号错误及性能优化
问题根源
- 直接拼接SQL字符串时,CSV内容中的**单引号(')**会破坏SQL语法结构,比如
O'Neil会被拼写成'O'Neil',导致SQL解析时判定引号未闭合。小文件刚好没包含这类特殊数据,所以未触发错误,大文件出现此类数据后就报错了。 - 循环逐条插入的方式在数据量大时,不仅性能极低,还容易因网络或连接波动出现额外异常。
方案1:参数化查询(解决语法错误+防注入)
参数化查询会自动处理单引号等特殊字符,彻底避免手动拼接SQL的语法问题,同时还能防止SQL注入风险。修改后的脚本如下:
$CSVImport = Import-CSV $PNP_CSV foreach ($CSVLine in $CSVImport) { $query = @" INSERT INTO PNP_Main (ItemId, ItemPath) VALUES(@ItemId, @ItemPath); "@ $params = @{ ItemId = $CSVLine.ItemId ItemPath = $CSVLine.Path } Invoke-Sqlcmd -Query $query -ServerInstance $Global:Server -Database $Global:Database -Parameter $params }
方案2:批量导入(大文件首选,提升性能)
对于10000条以上的数据,逐条插入效率极低,推荐用批量导入方式,速度快且能规避循环带来的问题。
方法A:使用SQL Server的BULK INSERT命令
$bulkQuery = @" BULK INSERT PNP_Main FROM '$PNP_CSV' WITH ( FIELDTERMINATOR = ',', ROWTERMINATOR = '\n', FIRSTROW = 2, -- 跳过CSV表头行 TABLOCK ); "@ Invoke-Sqlcmd -Query $bulkQuery -ServerInstance $Global:Server -Database $Global:Database
注意:需确保SQL Server服务账户有权限读取CSV文件,可将CSV放到服务器本地路径或共享目录。
方法B:使用PowerShell的SqlBulkCopy类(灵活处理数据)
适合需要在导入前做数据清洗、转换的场景:
$CSVImport = Import-CSV $PNP_CSV $connectionString = "Server=$Global:Server;Database=$Global:Database;Integrated Security=True;" $bulkCopy = New-Object Data.SqlClient.SqlBulkCopy($connectionString) $bulkCopy.DestinationTableName = "PNP_Main" $bulkCopy.BatchSize = 1000 # 每批插入1000条,可根据服务器性能调整 # 构建DataTable映射数据库列 $dt = New-Object Data.DataTable $dt.Columns.Add("ItemId", [string]) $dt.Columns.Add("ItemPath", [string]) foreach ($line in $CSVImport) { $row = $dt.NewRow() $row["ItemId"] = $line.ItemId $row["ItemPath"] = $line.Path $dt.Rows.Add($row) } $bulkCopy.WriteToServer($dt)
内容的提问来源于stack exchange,提问作者aasenomad
相关产品推荐
相关产品推荐

