【问题标题】:Error: Input array is longer than number of columns in this table powershell错误:输入数组长于此表 powershell 中的列数
【发布时间】:2017-09-03 02:27:07
【问题描述】:

我正在尝试将 160gb csv 文件加载到 sql 中,我正在使用从 Github 获得的 powershell 脚本,但出现此错误

    IException calling "Add" with "1" argument(s): "Input array is longer than the number of columns in this table."
At C:\b.ps1:54 char:26
+ [void]$datatable.Rows.Add <<<< ($line.Split($delimiter))
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

所以我用小 3 行 csv 检查了相同的代码,所有列都匹配,并且在第一行也有标题,没有额外的分隔符不知道为什么会出现这个错误。

代码如下

<# 8-faster-runspaces.ps1 #>
# Set CSV attributes
$csv = "M:\d\s.txt"
$delimiter = "`t"

# Set connstring
$connstring = "Data Source=.;Integrated Security=true;Initial Catalog=PresentationOptimized;PACKET SIZE=32767;"

# Set batchsize to 2000
$batchsize = 2000

# Create the datatable
$datatable = New-Object System.Data.DataTable

# Add generic columns
$columns = (Get-Content $csv -First 1).Split($delimiter) 
foreach ($column in $columns) { 
[void]$datatable.Columns.Add()
}

# Setup runspace pool and the scriptblock that runs inside each runspace
$pool = [RunspaceFactory]::CreateRunspacePool(1,5)
$pool.ApartmentState = "MTA"
$pool.Open()
$runspaces = @()

# Setup scriptblock. This is the workhorse. Think of it as a function.
$scriptblock = {
   Param (
[string]$connstring,
[object]$dtbatch,
[int]$batchsize
   )

$bulkcopy = New-Object Data.SqlClient.SqlBulkCopy($connstring,"TableLock")
$bulkcopy.DestinationTableName = "abc"
$bulkcopy.BatchSize = $batchsize
$bulkcopy.WriteToServer($dtbatch)
$bulkcopy.Close()
$dtbatch.Clear()
$bulkcopy.Dispose()
$dtbatch.Dispose()
}

# Start timer
$time = [System.Diagnostics.Stopwatch]::StartNew()

# Open the text file from disk and process.
$reader = New-Object System.IO.StreamReader($csv)

Write-Output "Starting insert.."
while ((($line = $reader.ReadLine()) -ne $null))
{
[void]$datatable.Rows.Add($line.Split($delimiter))

if ($datatable.rows.count % $batchsize -eq 0) 
{
   $runspace = [PowerShell]::Create()
   [void]$runspace.AddScript($scriptblock)
   [void]$runspace.AddArgument($connstring)
   [void]$runspace.AddArgument($datatable) # <-- Send datatable
   [void]$runspace.AddArgument($batchsize)
   $runspace.RunspacePool = $pool
   $runspaces += [PSCustomObject]@{ Pipe = $runspace; Status = $runspace.BeginInvoke() }

   # Overwrite object with a shell of itself
  $datatable = $datatable.Clone() # <-- Create new datatable object
}
}

# Close the file
$reader.Close()

# Wait for runspaces to complete
while ($runspaces.Status.IsCompleted -notcontains $true) {}

# End timer
$secs = $time.Elapsed.TotalSeconds

# Cleanup runspaces 
foreach ($runspace in $runspaces ) { 
[void]$runspace.Pipe.EndInvoke($runspace.Status) # EndInvoke method retrieves the results of the asynchronous call
$runspace.Pipe.Dispose()
}

# Cleanup runspace pool
$pool.Close() 
$pool.Dispose()

# Cleanup SQL Connections
[System.Data.SqlClient.SqlConnection]::ClearAllPools()

# Done! Format output then display
$totalrows = 1000000
$rs = "{0:N0}" -f [int]($totalrows / $secs)
$rm = "{0:N0}" -f [int]($totalrows / $secs * 60)
$mill = "{0:N0}" -f $totalrows

Write-Output "$mill rows imported in $([math]::round($secs,2)) seconds ($rs rows/sec and $rm rows/min)"

【问题讨论】:

  • 通常在这种情况下,此错误表明某些行具有意外的嵌入分隔符...选项卡,在这种情况下。这只是一些脏输入数据。您可以尝试读取行,用空字符串替换选项卡,然后通过比较原始大小和缩小大小来查看哪些行的选项卡比列的多。如果你有四列,你会期望一行缩小三个字符。
  • @Laughing Vergil 感谢您的回复,对逗号分隔的文件尝试了同样的操作,我得到了同样的错误
  • 您也可能对某些数据的行终止符有问题 - 在 Windows 样式的文本文件中间有一个 UNIX 样式的换行符,在一个数据检索操作中最终会出现两行。嵌入的换行符或 CR/LF 对也会扰乱您的处理。
  • 那么有什么办法可以解决这个问题吗?
  • 这是newlines上的一个答案

标签: sql sql-server powershell csv powershell-ise


【解决方案1】:

使用 160 GB 的输入文件会很痛苦。您无法真正将其加载到任何类型的编辑器中 - 或者至少在没有一些严格的自动化的情况下您不会真正分析这样的数据量。

根据 cmets,数据似乎存在一些质量问题。为了找到有问题的数据,您可以尝试二进制搜索。这种方法可以快速缩小数据。像这样,

1) Split the file in about two equal chunks.
2) Try and load first chunk.
3) If successful, process the second chunk. If not, see 6).
4) Try and load second chunk.
5) If successful, the files are valid, but you got another a data quality issue. Start looking into other causes. If not, see 6).
6) If either load failed, start from the beginning and use the failed file as the input file.
7) Repeat until you narrow down the offending row(s).

另一种方法是使用 ETL 工具,如 SSIS。将包配置为将无效行重定向到错误日志中,以查看哪些数据无法正常工作。

【讨论】:

  • SSIS 选项加 1。
猜你喜欢
  • 2019-03-27
  • 2018-08-21
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2021-02-23
  • 2015-06-02
  • 1970-01-01
相关资源
最近更新 更多