У меня есть стартовый CSV с примерами данных, например:
Underlying,AllBlue,AllRed
AUD,1/5/2024,
BRR,,
GBP, 3/10/2024,
CAD,,
Сегодня, 29.04.2024, с помощью другого процесса создается новый CSV, например, такой.
Underlying,AllBlue,AllRed
AUD,,
BRR,4/29/2024,
GBP,4/29/2024,
CAD,,4/29/2024
и я хочу добавить любые новые данные, найденные только в столбцах «AllBlue» и «AllRed», в исходный CSV. Желаемый результат будет
Underlying,AllBlue,AllRed
AUD,1/5/2024,
BRR ,4/29/2024,
GBP,4/29/2024,
CAD,,4/29/2024
Обратите внимание, как новые данные из CSV от 29 апреля 2024 г. перезаписываются в исходные. Кроме того, как ячейка GBP/AllBlue обновляется новой датой.
#sandbox testing
$CSVFiles = Get-ChildItem -Path "C:\Sandbox\test" -Filter "*.csv"
#put into array
$CSVData = @()
ForEach ($CSVFile in $CSVFiles) {
$CSVContent = Import-Csv -Path $CSVFile.FullName
$CSVData += $CSVContent
}
#output
$CSVData | Export-Csv -Path "C:\Sandbox\testoutput\colors.csv" -NoTypeInformation -Append
Это то, что я сейчас возвращаю.
"Underlying","AllBlue","AllRed"
"AUD","1/5/2024",""
"BRR","",""
"GBP","3/10/2024",""
"CAD","",""
"AUD","",""
"BRR","4/29/2024",""
"GBP","4/29/2024",""
"CAD","","4/29/2024"
Это добавляет данные, но не перезаписывает столбцы?. Я пробовал стирать несколько параметров, добавлять.
Отправленные вами данные не являются содержимым каких-либо файлов CSV. Похоже, вы пытались воспроизвести то, как они отображаются в конкретном приложении, вместо того, чтобы открывать их в текстовом редакторе, а затем копировать и вставлять сюда. Пожалуйста, замените их, когда вы Редактируете свой вопрос, включив в него свой код и информацию об отладке.
Пожалуйста, отредактируйте вопрос и скопируйте/вставьте вывод Get-Content -Path 'thefile.csv'
в виде текста. Никаких фотографий.
вопрос: что ТОЧНО содержит НОВЫЙ CSV? содержит ли он все строки оригинала, но с НЕКОТОРЫМИ разными значениями? Содержит ли он НЕКОТОРЫЕ строки оригинала с НЕКОТОРЫМИ разными значениями?
Это один из способов получить желаемый результат. Встроенные комментарии должны помочь в мыслительном процессе.
# Import-Csv here instead
$sourceCsv = ConvertFrom-Csv @'
Underlying,AllBlue,AllRed
AUD,1/5/2024,
BRR,,
GBP, 3/10/2024,
CAD,,
'@
# Import-Csv here instead
$newCsv = ConvertFrom-Csv @'
Underlying,AllBlue,AllRed
AUD,,
BRR,4/29/2024,
GBP,4/29/2024,
CAD,,4/29/2024
ThisIsALineToAppend,,4/29/2024
'@
# create a hashtable using the Underlying property as keys
$map = $sourceCsv | Group-Object Underlying -AsHashTable
$linesToAppend = foreach ($line in $newCsv) {
# if the Underlying value of the new Csv exists in the old CSV
if ($map.ContainsKey($line.Underlying)) {
# get the object having the same Underlying value of the old CSV
$value = $map[$line.Underlying][0]
# if the AllBlue of the new CSV is not null
if (-not [string]::IsNullOrWhiteSpace($line.AllBlue)) {
# update the object of the old CSV with this new value
$value.AllBlue = $line.AllBlue
}
# if the AllRed of the new CSV is not null
if (-not [string]::IsNullOrWhiteSpace($line.AllRed)) {
# update the object of the old CSV with this new value
$value.AllRed = $line.AllRed
}
# go to the next iteration
continue
}
# else, this Underlying doesn't exist in the old CSV
# so its gotta be appended
$line
}
$sourceCsv + $linesToAppend | ConvertTo-Csv
Это работает так, как ожидалось. Большое спасибо за комментарии к сценарию Сантьяго. Это очень помогает.
@iceman рад, что это было полезно. помните, что если это решит вашу проблему, вы можете принять ответ
Это расширяет ответ @Santiago. Это позволит нескольким полям составлять составной ключ для каждой строки. Он также будет сравнивать все неключевые поля, не требуя их жесткого кодирования. Это несложно, если есть два (2) поля для сравнения. Гораздо сложнее, если нужно сравнить восемьдесят два (82) поля.
$NaturalKey = @('Underlying','New')
# Import-Csv here instead
$sourceCsv = ConvertFrom-Csv @'
Underlying,New,AllBlue,AllRed
AUD,9,1/5/2024,
BRR,8,,
GBP,7, 3/10/2024,
CAD,6,,
'@
# Import-Csv here instead
$newCsv = ConvertFrom-Csv @'
Underlying,New,AllBlue,AllRed
AUD,9,,
BRR,8,4/29/2024,
GBP,7,4/29/2024,
CAD,6,,4/29/2024
ThisIsALineToAppend,5,,4/29/2024
'@
# Compare the fields of both CSV files to ensure that they have the names.
# The fields do not need to be in the same order.
$SourceFields = $sourceCsv[0].psobject.Properties.name | Sort-Object
$NewFields = $newCsv[0].psobject.Properties.name | Sort-Object
if ($null -ne (Compare-Object -ReferenceObject $sourceFields -DifferenceObject $NewFields)) {
Write-Error -Message 'CSV files do not have the same field names or number of fields."'
return 1
}
# Only test for new values in the fields that are not part of the natural key.
$FieldsToCompare = foreach ($Field in $NewFields) { if ($Field -notin $NaturalKey) { $Field }}
# create a hashtable using the Underlying property as keys
$map = $sourceCsv | Group-Object $NaturalKey -AsHashTable -AsString
# Iterate over all rows of the new CSV file.
$linesToAppend = foreach ($line in $newCsv) {
# Gather the fields comprising the natural key.
$KeyValues = foreach ($k in $NaturalKey) { $line.$k }
$Key = $KeyValues -join ', '
# if the natural key value of the new Csv exists in the old CSV
if ($map.ContainsKey($Key)) {
# get the object having the same Underlying value of the old CSV
$value = $map[$Key][0]
# Iterate over the fields to be compared (all fields except those in the natural key).
foreach ($Field in $FieldsToCompare) {
# If the new field valus is not null or whitespace, replace the existing value.
if (-not [string]::IsNullOrWhiteSpace($line.$Field)) {
$value.$Field = $line.$Field
}
}
} else {
# else, this Underlying doesn't exist in the old CSV
# so its gotta be appended
$line
}
}
$sourceCsv + $linesToAppend | ConvertTo-Csv
Были ли какие-либо попытки кодирования, которые вы уже пробовали? и если да, пожалуйста, добавьте это в свой вопрос