2016-11-07 110 views
0

我讀過一篇名爲「使用PowerShell C#或VB Net高效地將大型CSV導入SQL Server」的文章。我正在使用文章中的PowerShell腳本,我有3個我不明白的錯誤。將大型CSV文件導入到SQL服務器失敗

我創建了只有21個條目的csv文件的小版本。我有一個SQL Server表,我需要從CSV文件導入數據。 CSV文件將在夜間從Oracle數據庫中提取,並將其導入到另一個程序使用的SQL Server表中。

我拿了腳本,並用它對5列的21行數據集,所有這些都是10個字符寬。在最後一列數據中不能輸入,這就是爲什麼我將它包含在數據集中的原因。我使用SSMS在數據庫中創建了一個表CMWBACCT,我在我的機器上創建了CCBCMWB,以及我試圖導入數據的表。現實生活中的CSV文件約爲150萬行,對於我工作的3個表格中的每一個。我使用的程序是文章中的程序,但只是修改了一個表格。

第一個錯誤是在腳本的第38行:

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

其中PowerShell不喜歡-First

獲取內容:參數無法找到匹配的參數名稱「第一」 。 在C:\ CMWBTST \輸入-CSVtoSQLA.ps1:38字符:40分 + $列=(獲取內容$ csvfile - 第一< < < < 1).Split($ csvdelimiter) + CategoryInfo:InvalidArgument:(: )[獲取內容],ParameterBin dingException + FullyQualifiedErrorId:NamedParameterNotFound,Microsoft.PowerShell.Comm ands.GetContentCommand

第二誤差我明白甚至更少它發生在線路48上:

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

並且發生21倍

異常調用「添加」和「1」的說法(S):「輸入陣列比在該表的列的n個 棕土長。」 在C:\ CMWBTST \輸入-CSVtoSQLA.ps1:48個字符:32 + $ NULL = $ datatable.Rows.Add < < < <($ line.Split($ csvdelimiter)) + CategoryInfo:NotSpecified:(: )[],MethodInvocationException + FullyQualifiedErrorId:DotNetMethodException

該數組包含其中列的數目相匹配表中的,所以我很困惑五個字段。

最後錯誤的程序在65行不太願意:與錯誤

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

的我缺少的方法Dispose

方法調用失敗,因爲[System.Data.SqlClient.SqlBulkCopy]不包含名爲「Dispose」的方法。 在C:\ CMWBTST \ Import-CSVtoSQLA.ps1:65 char:37 + $ bulkcopy.Close(); $ bulkcopy.Dispose < < < <() + CategoryInfo:InvalidOperation:(處置:字符串)[],RuntimeEx ception + FullyQualifiedErrorId:MethodNotFound

在哪裏被定義該方法應該?

下面是我使用的腳本:

#################################################### 
#             # 
# 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() 

和使用

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 

任何幫助將不勝感激

+3

['GET-Content'(https://technet.microsoft.com/library/hh847788.aspx)沒有一個參數' - 第一個'所以劇本剛剛壞了。可能該位應該說'Get-Content |選擇-First 1'來獲取文件的第一行。在閱讀失敗的列後,它拋出關於表中列數的錯誤並不奇怪。嘗試做出改變並重新運行,看看它有哪些新錯誤? – TessellatingHeckler

回答

-1

我建議使用進口-CSV PowerShell中的CSV(文本)文件命令從CSV文件導入數據,因爲它是處理csv格式文件的官方方法。該cmdlet的語法非常簡單。

Import-Csv -Path target.csv -Delimiter , 

要將數據導入數據庫,可以在PowerShell中使用SQL Server PowerShell模塊而不是ADO.NET。

Invoke-Sqlcmd -Query "<sql statements>" 

你可以看到這篇文章How to use SQL Server PowerShell Module to import data from CSV file下載樣本