与另一个文件相比,我正在尝试从一个文件中提取一些数据。我需要在Powershell中进行此操作。我真的是在试图哄骗一些SQL之类的工作,而且,尽管我抓挠头,继续阅读有关该主题的文章,但我仍然无能为力。
基本上,我需要将文件1中的4条条件匹配到文件2中的4条条件。如果匹配,我需要确保文件2中的其他2条条件满足某些值。
如果条件匹配且值满足,则我希望这些事务在一个文件中,否则在另一个文件中。
文件1与文件2匹配的条件
公司编号:$_.File1Field1
至$_.File2Field4
交易号:$_.File1Field8
至$_.File2Field1
的后4位
交易值:从$_.File1Field11
到$_.File2Field10
交易日期:$_.File1Field7
至$_.File2Field7
如果这4个条件匹配,则我需要在文件2上增加2个额外字段,例如$_.File2Field2
不能为“ ABC”或“ DEF”,$_.File2Field3
不能为“ 1234”。
然后,我需要在一个文件中进行一种类型的所有事务,而在另一文件中进行其他事务。 我对Powershell的要求是否太高(我肯定对那个问题的要求太高了!!!!!)?
我已经做了很多关于Compare-Object和Where-Object的阅读,但是找不到任何我可以使用的东西。 :(
这些是我目前的原始文件。
#File 1:
$LoanTransactions = import-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Test_Store_Loans_Module.txt
#File 2:
$LoanExtract = import-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\loans_extract.csv
我在过去曾经做过where-object的工作,在这里我会预定义一些条件,然后将其应用到文件中以提取结果,但是我无法使条件取决于其中包含的某些内容。我的第二个文件。
类似的东西:
$ConditionsToMeet = { $_.File1Field1 -eq $_.File2Field4 -and $_.File1Field8 -eq $_.File2Field1.....}
$ConditionsNotMet = { $_.File1Field1 -ne $_.File2Field4 -or $_.File1Field8 -ne $_.File2Field1.....}
$LoanTransactions | where-object $ConditionsToMeet | Export-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Extract1.txt
$LoanTransactions | where-object $ConditionsNotMet | Export-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Extract2.txt
很显然,不幸的是,尽管阅读了很多书,但我的条件却不正确,我找不到方法。 它可能非常简单,或者也许Powershell不能完全做到这一点,但是我认为这应该可以实现?
答案 0 :(得分:0)
我将假设为每行值提供保证唯一的公司编号,交易号,交易日期和交易值。换句话说,它们将构成SQL表中的键。坦白地说,我的假设是“交易价值”实际上并不是密钥的一部分,而是两个文件之间的数据一致性检查。如果这些假设中的任何一个都不正确,则此解决方案可能对您不起作用。但是,如果是这种情况,那么您的问题可能是不确定的。也就是说,您的数据文件可能没有足够的信息来实际解决问题。
Compare-Object
在这里无法正常工作。这是一个非常容易处理的命令,在大多数应用程序中表现不佳。
最简单的答案可能是“将数据文件加载到SQL数据库并运行查询”。最终,即使您正在考虑使用SQLite数据库,也可能是最好的选择。
但是,假设您必须使用PowerShell执行此操作。最简单的方法是采用简单,暴力的方法:
#File 1:
$LoanTransactions = Import-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Test_Store_Loans_Module.txt
#File 2:
$LoanExtract = Import-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\loans_extract.csv
# Find all transactions to save to Extract1
$Extract1 = foreach ($Tran in $LoanTransactions) {
foreach ($Extract in $LoanExtract) {
if (
($Tran.File1Field1 -eq $Extract.File2Field4) -and
($Tran.File1Field8 -eq $Extract.File2Field1) -and
($Tran.File1Field11 -eq $Extract.File2Field10) -and
($Tran.File1Field7 -eq $Extract.File2Field7) -and
($Extract.File2Field2 -notin ('ABC','DEF')) -and
($Extract.File2Field3 -ne '1234')
) {
$Tran
}
}
}
# Find all transactions not in Extract1 and save them to Extract2
$Extract2 = foreach ($Tran in $LoanTransactions) {
$FoundInExtract1 = $false
foreach ($Extract in $Extract1) {
if (
($Tran.File1Field1 -eq $Extract.File2Field4) -and
($Tran.File1Field8 -eq $Extract.File2Field1) -and
($Tran.File1Field11 -eq $Extract.File2Field10) -and
($Tran.File1Field7 -eq $Extract.File2Field7)
) {
$FoundInExtract1 = $true
}
}
if (-not $FoundInExtract1) {
$Tran
}
}
$Extract1 | Where-Object $ConditionsToMeet | Export-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Extract1.txt -NoTypeInformation
$Extract2 | Where-Object $ConditionsNotMet | Export-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Extract2.txt -NoTypeInformation
您可以通过使用哈希表作为索引来加快处理过程,从而变得更聪明。基本上,我们要做的是将$LoadExtract
加载到嵌套的哈希表中。哈希表可用于非常快速键查找。建立表应该相对较快。使用在主键中具有6个字段的本地数据库表,大约需要12秒来处理175,000条记录,但是您的里程可能会有所不同。这里有很多变量。
脚本一旦建立,就可以很容易地在File2中针对File1中的值进行查找。该代码有点丑陋,但其性能应与PowerShell差不多。
接下来要记住的是,Import-Csv
将所有内容导入为纯文本。这意味着格式中包括重要的尾随空格。此外,哈希表可识别数据类型。 $hash[1234]
与$hash['1234']
不同。如果数据类型和数据值不完全匹配 ,您将无法正确执行查找,因此您需要确保用于键的字段完全相同。您唯一不必担心的是区分大小写。其他所有事情都很重要,因为没有隐式数据转换。
请注意,在下面的代码中,我不小心交换了交易日期和交易值。这实际上并不会影响其功能,但会使其更加混乱。我责怪那些真正糟糕的字段名。
首先,我们将从文件2中设置哈希表:
#File 1:
$LoanTransactions = Import-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Test_Store_Loans_Module.txt
#File 2:
$LoanExtract = Import-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\loans_extract.csv
#Hash table to be used for Loan Extract lookups
$LoanExtractTable = @{}
#Build the loan extract table nested hash table
$LoanExtract | ForEach-Object {
# Company Number
if (!$LoanExtractTable.ContainsKey($_.File2Field4)) {
$LoanExtractTable[$_.File2Field4] = @{}
}
# Transaction Number
if (!$LoanExtractTable[$_.File2Field4].ContainsKey($_.File2Field1)) {
$LoanExtractTable[$_.File2Field4][$_.File2Field1] = @{}
}
# Transaction Date
if (!$LoanExtractTable[$_.File2Field4][$_.File2Field1].ContainsKey($_.File2Field7)) {
$LoanExtractTable[$_.File2Field4][$_.File2Field1][$_.File2Field7] = @{}
}
# Transaction Value
# This is the last key, so we save our data here.
if (!$LoanExtractTable[$_.File2Field4][$_.File2Field1][$_.File2Field7].ContainsKey($_.File2Field10)) {
$LoanExtractTable[$_.File2Field4][$_.File2Field1][$_.File2Field7][$_.File2Field10] = $_
}
}
因此,如果我们拥有公司编号57
,交易编号为123456
,交易日期为2019-11-30
,交易金额为123.45
,则可以看起来像这样:
$LoanExtractTable['57']['123456']['2019-11-30']['123.45']
再次注意,这里的所有内容都是一个字符串。格式对于日期和货币值很重要。但是,在下面的代码中,我们需要回到ContainsKey()
并再次嵌套if语句,因为我们需要查找记录的存在。如果感觉像我们正在构建SQL样式索引并进行联接,那是因为我们基本上是。
现在,我们可以遍历交易文件。
foreach ($LoanTransaction in $LoanTransactions) {
$ValidExtract = $false
# Company Number
if ($LoanExtractTable.ContainsKey($LoanTransaction.File1Field1)) {
# Transaction Number
if ($LoanExtractTable[$LoanTransaction.File1Field1].ContainsKey($LoanTransaction.File1Field8)) {
# Transaction Date
if ($LoanExtractTable[$LoanTransaction.File1Field1][$LoanTransaction.File1Field8].ContainsKey($LoanTransaction.File1Field7)) {
# Transaction Value
if ($LoanExtractTable[$LoanTransaction.File1Field1][$LoanTransaction.File1Field8][$LoanTransaction.File1Field7].ContainsKey($LoanTransaction.File1Field11)) {
# It's in the LoanExtract file! Now we can do our additional data checks
if (
$LoanExtractTable[$LoanTransaction.File1Field1][$LoanTransaction.File1Field8][$LoanTransaction.File1Field7][$LoanTransaction.File1Field11].File2Field2 -notin @('ABC','DEF')
-and $LoanExtractTable[$LoanTransaction.File1Field1][$LoanTransaction.File1Field8][$LoanTransaction.File1Field7][$LoanTransaction.File1Field11].File2Field3 -ne '1234')
) {
# It's valid to export to Extract1.txt
$ValidExtract = $true
$LoanTransaction | Export-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Extract1.txt -Append -NoTypeInformation
}
}
}
}
}
if ($ValidExtract -eq $false) {
$LoanTransaction | Export-Csv \\774512-LRBSPT01\********$\uardata\rt1\BankRec\Test\step1\Extract2.txt -Append -NoTypeInformation
}
}
这里肯定有优化和改进的空间。我不知道您的数据是什么样子,但是我不得不认为上面字段的顺序非常糟糕。我认为交易日期,公司编号,交易编号,交易价值会更好。
此外,您可以轻松地将File2Field2
和File2Field3
的测试移至要构建哈希表的位置,但是我不确定这就是您正在做的一切。
写入数据的方式也不是最理想的,但是它可能比迭代两次或使用带有+=
的数组连接更好。至少这可以使用磁盘缓冲区。
上面的代码不很简单,但是它就像我能想到的那样简单,而无需让PowerShell对文件1的每一行都通过File2进行迭代(即执行笛卡尔积),如果两个文件都很大,可能会非常慢。