【问题标题】:Import Script for Large CSV files into SQL server Failing将大型 CSV 文件的脚本导入 SQL 服务器失败
【发布时间】:2016-11-07 17:12:13
【问题描述】:

我阅读了一篇名为“使用 PowerShell C# 或 VB Net 将大型 CSV 有效地导入 SQL Server”的文章。我正在使用文章中的 PowerShell 脚本,但有 3 个我不理解的错误。

我创建了一个只有 21 个条目的 csv 文件的小版本。我有一个 SQL Server 表,我需要将数据从 CSV 文件导入。 CSV 文件将在每晚创建,因为它从 Oracle 数据库中提取并将其导入到另一个程序使用的 SQL Server 表中。

我将脚本用于 21 行 5 列的数据集,所有这些数据集都是 10 个字符宽。最后一列数据不能有条目,这就是我将其包含在数据集中的原因。我使用 SSMS 在数据库 CCBCMWB 中创建了一个表 CMWBACCT,该表是我在我的机器上创建的,以及我试图将数据导入的表。对于我正在使用的 3 个表中的每一个,现实生活中的 CSV 文件大约有 150 万行。我使用的程序是文章中的程序,但仅针对一张表进行了修改。

第一个错误在脚本的第 38 行:

$columns = (Get-Content $csvfile -First 1).Split($csvdelimiter) 

PowerShell 不喜欢 -First

Get-Content:找不到与参数名称“First”匹配的参数。 在 C:\CMWBTST\Import-CSVtoSQLA.ps1:38 char:40 + $columns = (Get-Content $csvfile -First

我理解的第二个错误发生在第 48 行时更少:

$null = $datatable.Rows.Add($line.Split($csvdelimiter)) 

并且出现了 21 次

使用“1”参数调用“Add”的异常:“输入数组比 n 长 此表中的列数。” 在 C:\CMWBTST\Import-CSVtoSQLA.ps1:48 char:32 + $null = $datatable.Rows.Add

该数组包含五个字段,这些字段与表中的列数相匹配,所以我很困惑。

程序在第 65 行停止的最后一个错误:

$bulkcopy.Close(); $bulkcopy.Dispose() 

由于错误,我缺少方法Dispose

方法调用失败,因为 [System.Data.SqlClient.SqlBulkCopy] 不包含名为“Dispose”的方法。 在 C:\CMWBTST\Import-CSVtoSQLA.ps1:65 char:37 + $bulkcopy.Close(); $bulkcopy.Dispose

这个方法应该在哪里定义?

以下是我使用的脚本:

#################################################### 
#                                                  #
# PowerShell CSV to SQL Import Script              #
#                                                  #
#################################################### 

# Database variables 
$sqlserver = "EMRICHRT3400" 
$database = "CCBCMWB" 
$table = "CMWBACCT" 

# CSV variables 
$csvfile = "C:\CMWBTST\CMWBACCT21.csv" 
$csvdelimiter = "," 
$FirstRowColumnNames = $false 

################### 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 0) {  
        $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()

以及使用的 CSV(文本)文件

0000050590,1390457725,2013-01-02,2016-03-07,2016-06-06
0000100491,8156952728,2008-12-16,2016-04-01,2016-07-01
0000120293,0000120000,2006-11-15,2016-02-18,2016-05-19
0000220299,0000220000,2006-10-11,2016-04-15,2016-07-15
0000340706,0000340000,2009-03-12,2016-02-24,2016-05-25
0000420610,9760303504,2012-05-16,2016-04-15,2016-07-15
0000500613,0000500000,2006-12-06,2016-03-01,2016-06-03
0000740524,0000740000,2006-10-18,2016-04-25,2016-07-25
0001030634,0001030000,2006-11-16,2016-02-18,2016-05-19
0001120239,0001120000,2006-12-14,2016-03-17,2016-06-17
0001150542,0001150000,2006-11-16,2016-02-18,2016-05-19
0001220144,0001220000,2006-10-10,2016-04-15,2016-07-15
0001240146,2947199958,2011-09-26,2016-04-07,2016-07-08
0001520257,7724424991,2012-12-17,2016-04-15,2016-07-15
0001530858,0001530000,2006-12-20,2016-03-22,2016-06-27
0001620362,0001620000,2006-10-16,2016-04-20,2016-07-20
0001700965,0001700000,2006-12-04,2016-03-03,2016-06-08
0001730768,0001730000,2006-10-10,2016-04-07,2016-07-07
0001910075,6494797239,2016-05-17,,
0001920876,0001920000,2006-10-31,2016-05-03,2016-08-03
0002140587,5733138981,2013-02-01,2016-04-14,2016-07-14

任何帮助将不胜感激

【问题讨论】:

  • Get-Content 没有参数 -First 所以脚本只是坏了。可能该位应该说Get-Content | Select -First 1 以获取文件的第一行。读取列失败后,它会抛出有关表中列数的错误也就不足为奇了。尝试进行更改并重新运行,看看它有什么新错误?

标签: sql-server powershell csv


【解决方案1】:

我建议使用 Import-Csv PowerShell 命令从 CSV 文件导入数据,因为它是处理 csv 格式文件的官方方法。并且cmdlet的语法非常简单。

Import-Csv -Path target.csv -Delimiter ,

对于将数据导入数据库,您可以使用 SQL Server PowerShell 模块而不是 PowerShell 中的 ADO.NET。

Invoke-Sqlcmd -Query "<sql statements>"

您可以阅读这篇文章How to use SQL Server PowerShell Module to import data from CSV file下载示例

【讨论】:

    猜你喜欢
    • 2018-03-10
    • 2018-07-28
    • 2017-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多