使用 Powershell 将大型 CSV 批量导入 SQL Server

Posted

技术标签:

【中文标题】使用 Powershell 将大型 CSV 批量导入 SQL Server【英文标题】:Using Powershell to Bulk Import Large CSV into SQL Server 【发布时间】:2018-01-18 14:32:44 【问题描述】:

我看到一篇帖子,讨论如何使用 Powershell 相对快速地批量导入海量数据。我有一个典型的 csv 文件,其中大约有 500 万行以通常的方式格式化。

无论我选择导入 txt 还是 csv 文件,我都会不断收到相同的错误消息。使用 csvdelimiter/firstcolumnnames 部分也产生了他们自己的问题。

我花了几个小时试图弄清楚如何让它与我的 csv 文件一起工作,但无论我尝试什么,我都会收到相同的错误消息。所有字段名称都接受 Null 并且它们在表和 csv 文件之间的所有方面都是相同的。我没有数据库的主键。

# Database variables
$sqlserver = "SERVERNAMEHERE"
$database = "autos"
$table = "AgedAutos"

# CSV variables
$csvfile = "C:\temp\aged.csv"
$csvdelimiter = "',"
$firstRowColumnNames = $true

################### No need to modify anything below ###################
Write-Host "Script started..."
$elapsed = [System.Diagnostics.Stopwatch]::StartNew() 
[void][Reflection.Assembly]::LoadWithPartialName("System.Data")
[void][Reflection.Assembly]::LoadWithPartialName("System.Data.SqlClient")

# 50k worked fastest and kept memory usage to a minimum
$batchsize = 50000

# Build the sqlbulkcopy connection, and set the timeout to infinite
$connectionstring = "Data Source=$sqlserver;Integrated Security=true;Initial Catalog=$database;"
$bulkcopy = New-Object Data.SqlClient.SqlBulkCopy($connectionstring, [System.Data.SqlClient.SqlBulkCopyOptions]::TableLock)
$bulkcopy.DestinationTableName = $table
$bulkcopy.bulkcopyTimeout = 0
$bulkcopy.batchsize = $batchsize

# Create the datatable, and autogenerate the columns.
$datatable = New-Object System.Data.DataTable

# Open the text file from disk
$reader = New-Object System.IO.StreamReader($csvfile)
$columns = (Get-Content $csvfile -First 1).Split($csvdelimiter)
if ($firstRowColumnNames -eq $true)  $null = $reader.readLine() 

foreach ($column in $columns)  
    $null = $datatable.Columns.Add()


# Read in the data, line by line
while (($line = $reader.ReadLine()) -ne $null)  
    $null = $datatable.Rows.Add($line.Split($csvdelimiter))
    $i++; if (($i % $batchsize) -eq 1)  
        $bulkcopy.WriteToServer($datatable) 
        Write-Host "$i rows have been inserted in $($elapsed.Elapsed.ToString())."
        $datatable.Clear() 
     
 

# Add in all the remaining rows since the last clear
if($datatable.Rows.Count -gt 0) 
         $bulkcopy.WriteToServer($datatable)
         $datatable.Clear()


# Clean Up
$reader.Close(); $reader.Dispose()
$bulkcopy.Close(); $bulkcopy.Dispose()
$datatable.Dispose()

Write-Host "Script complete. $i rows have been inserted into the database."
Write-Host "Total Elapsed Time: $($elapsed.Elapsed.ToString())"
# Sometimes the Garbage Collector takes too long to clear the huge datatable.
[System.GC]::Collect()

下面列出的错误消息。

Exception calling "WriteToServer" with "1" argument(s): "The given value of type String from the data source cannot be converted to 
type date of the specified target column."
At C:\powershell_scripts\batch_csv_import-code1-working-test for auto table.ps1:43 char:3
+         $bulkcopy.WriteToServer($datatable)
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException

340000 rows have been inserted in 00:00:03.5156162

我不知道这个错误是什么意思,因为我在 Google 上找不到任何有用的东西。我在想其中一列可能在 SQL Server 中列出不正确,但我可能是错的。

请帮我找出问题所在。谢谢。

【问题讨论】:

我认为 SSIS 将是最好的工具。将 CSV 导入数据库表是 ETL 101,SSIS 性能非常适合此类任务。 某处映射到日期字段的字符串具有无效值。 好消息是我发现了这个问题。其中一列未正确标注。简单的调整,现在效果很好。坏消息是所有数据都被导入第一列,而不是被拆分到我数据库中的不同列中。有谁知道我可以使用上述代码使用什么命令来忽略在单个单元格中发现的任何逗号?我在这里找到的唯一东西是几年前的,我无法让它工作。 link @J.R. - 正则表达式是在 .NET 中解析真正 CSV 的唯一“内置”方式。如果这不起作用或太慢,请尝试以下库:***.com/questions/1941392/… 【参考方案1】:

您正在获取第一列中的所有数据,因为您的 $csvdelimiter 值不正确。 你有: $csvdelimiter = "'," 它应该是:$csvdelimiter = ","

【讨论】:

以上是关于使用 Powershell 将大型 CSV 批量导入 SQL Server的主要内容,如果未能解决你的问题,请参考以下文章

Powershell 批量导入AD账户

powershell 使用FAF技术(批量数据集和内联多线程)快速CSV到SQL Server导入

powershell合并csv

office 365通过PowerShell批量添加共享邮箱成员

Powershell - 针对大型目录运行脚本时出现内存不足错误

使用powershell批量导入AD用户