我是一名软件专家,但是在我第二周的PowerShell知识中。
我们有一组12个固定宽度的格式文件,其中包含人员列表(记录可能是重复的)。这些文件大约为800MB,总计行数约为1400万。查看第一个文件,它包含1,201,940行。
此外,我们有一个应该包含所有数据(不同记录)的SQL表。我的任务是使用PowerShell通过将源文件中的一些选择字段与SQL表进行比较,然后将任何丢失的记录写入CSV日志来确保数据完全加载。
让我们假设我感兴趣的字段是ID,FirstName,LastName,并且对于所有情况我限制我的对象/查询只考虑那些字段。
比较数据的PowerShell中最理想的方法是什么?您是将数据捆绑到SQL,使其完成工作,然后检索结果,还是将所有数据捆绑到PowerShell并在那里进行处理?
我想到了以下想法,但没有测试过它们:
@fileInfo
)。从文件(DataTable
)创建$dtFile
。使用$dtFile
,对于每X行数,请加载@fileInfo
。在LEFT JOIN
和SQL表之间执行@fileInfo
,并将结果推送到DataTable($dtResults
)。将$dtResults
写入日志。清空@fileInfo
的内容以准备下一次循环迭代。这似乎是我最好的主意。DataTable
)创建$dtFile
。使用$dtFile
,对于每X行,构造一个SQL select语句,该语句具有可怕的WHERE
子句,用于限制数据库返回的行。推送到另一个DataTable($dtSQL
)。比较两者并记录$dtFile
中未出现在$dtSQL
中的任何条目。看起来很粗糙,但很有效。DataTable
。批量将它们插入SQL临时表,LEFT JOIN
对SQL表,检索结果并将结果写入日志。我想我会因为通过网络推送大量数据而陷入困境DataTable
,将文件中的所有记录加载到第二个DataTable
,比较PowerShell中的结果并将结果写入日志。我假设我的内存不足......?我会为每个解决方案创建脚本并自己做一个测试,但是我处于紧张状态并且没有奢侈品。是不是总是那种情况?
修改:我发布了一个适用于我的解决方案
答案 0 :(得分:1)
我会在数据库引擎上完全卸载比较:
Import-CsvToSql
(或bcp
)等内容将数据批量加载到SQL中的新表fileTable
fileTable
与originalTable
using UNION ALL
(见下文)根据底层存储,您可能希望将原始表复制到数据库,您可以在从数据库导入数据集之前将恢复模型切换为SIMPLE或BULK_LOGGED
基于UNION ALL的比较程序看起来像:
SELECT MIN(TableName) as TableName, ID, FirstName, LastName
FROM
(
SELECT 'Database' as TableName, originalTable.ID, originalTable.FirstName, originalTable.LastName
FROM originalTable
UNION ALL
SELECT 'Files' as TableName, fileTable.ID, fileTable.FirstName, fileTable.LastName
FROM fileTable
) tmp
GROUP BY ID, FirstName, LastName
HAVING COUNT(*) = 1
ORDER BY ID
答案 1 :(得分:0)
很抱歉所有人都没有及时回复,但我有一个解决方案!最可能的改进空间,但解决方案相当快。我没有权限访问我的数据库直接运行PowerShell,所以我最后使用了SQL导入和导出向导。
流程摘要:
<强>详细强>
使用对象数组在脚本中导入数据点。
$dataPoints = Import-Csv "c:\temp\datapoints.csv"
$objDataCols = @()
foreach($objCol in $dataPoints){
objColumn = New-Object psobject
$objColumn | Add-Member -Type NoteProperty -Name Name -Value $objCol.Name
$objColumn | Add-Member -Type NoteProperty -Name Position -Value ([int] $objCol.Position)
$objColumn | Add-Member -Type NoteProperty -Name ColumnLength -Value ([int] $objCol.ColumnLength)
$objSourceCols += $objColumn
}
查找文件并将名称组合到一个数组(可选)。我使用正则表达式来过滤我的文件。
$files = @()
Get-ChildItem -Path $sourceFilePath | Where-Object { $_.FullName -match $regExpression } | ForEach-Object{
$files += $_.FullName
}
循环遍历每个文件并将其解析为输出文件。在生产代码中,您需要try / catch块,但我在示例中将它们遗漏了。
$writer = New-Object System.IO.StreamWriter "c:\temp\outputFile.txt"
ForEach($sourceFileName in $files){
$reader = [System.IO.File]::OpenText($sourceFileName)
while($reader.Peek() -gt -1){
$line = $reader.ReadLine()
# Write each data point in the line, pipe delimited
for($i = 0; $j -le ($objDataCols).Length; $i++){
# Write to a pipe-delimited file
$writer.Write("{0}|", $line.Substring($objDataCols[$i].Position, $objDataCols[$i].ColumnLength))
}
# Write a new line, along with any additional reference columns not defined in the source file, such as adding in the source file name and line number
$writer.WriteLine($sourceFileName)
}
$reader.Close()
$reader.Dispose()
}
$writer.Close()
$writer.Dispose()
将竖线分隔的输出文件导入SQL。