2015-10-30 28 views
0

我已經繼承了一點亂七八糟。我有不同的用戶數據的多個CSV文件。我需要找到一種方法將所有信息彙總成一個文件,而且我不想花費數小時來完成。問題是並非所有的用戶都是相同的,並且它們的順序不同。是否有一種簡單的方法將第二個文件中的字段拉到第一個文件中用戶名匹配的另一個文件中?我確信我沒有正確描述這一點,只是開始。MAP CSV用戶數據分離CSV

例如: 文件1個

username,first,last,phone number 
john.do,John,Doe,8888675309 
jack.jo,Jack,Johnson,5378984687 
harry.po,Harry,Potter,9876543219 

文件2

username,first,last,email 
john.do,John,Doe,[email protected] 
sandy.mi,Sandy,Michaels,[email protected]  
jack.jo,Jack,Johnson,[email protected] 
harry.po,Harry,Potter,[email protected] 
+4

就我個人而言,我可能會將它們導入SQL數據庫並加入表格。實際上,您可能需要查看[Join-Object](http://blogs.msdn.com/b/powershell/archive/2012/07/13/join-object.aspx)。 –

+0

我給出了大致相同的問題[這裏]的回答(http://stackoverflow.com/a/17027718/608772)。 – JPBlanc

+0

關於連接對象的博客剛剛進入我的收藏夾列表。我打算閱讀並學習這一點。第一部分似乎是對第一,第二和第三範式的回顧,儘管它並沒有這樣說。謝謝! –

回答

1

把它當作你,這個要結合多個CSV文件。請注意,它可能並不快,但應該徹底。

$CSVList = 'C:\Path\To\Users1.csv','C:\Path\To\Users2.csv','C:\Path\To\Users3.csv','C:\Path\To\Users4.csv','C:\Path\To\Users5.csv' 
$PrimaryTable = @{} 
Import-CSV $CSVList[0] | %{$PrimaryTable.Add($_.UserID,$_)} 
$PrimaryKeys = $PrimaryTable.Values[0] | Get-Member -MemberType Properties | Select -ExpandProperty Name 
ForEach($CSVFile in ($CSVList|Select -Skip 1)){ 
    $Users = Import-CSV $CSVFile 
    $Keys = $Users[0] | Get-Member -MemberType Properties | Select -ExpandProperty Name 
    $KeysToAdd = @{} 
    $Keys|?{$_ -notin $PrimaryKeys}|%{$KeysToAdd.Add($_,"")} 
    $PrimaryTable.Values|%{$_|Add-Member -NotePropertyMembers $KeysToAdd} 
    ForEach($User in $Users){ 
     If(!($User.UserID -in $PrimaryTable.Keys)){ 
      $PrimaryKeys | ?{$_ -notin $Keys} | %{add-member -InputObject $User -NotePropertyName $_ -NotePropertyValue ""} 
      $PrimaryTable.Add($User.UserID,$User) 
     }Else{ 
      $Keys | ?{[string]::IsNullOrWhiteSpace($PrimaryTable.($User.UserID).$_)} | %{$PrimaryTable.($User.UserID).$_ = $User.$_} 
     } 
    } 
    $PrimaryKeys = $PrimaryTable.Values[0] | Get-Member -MemberType Properties | Select -ExpandProperty Name 
} 

$PrimaryTable.Values|Export-CSV C:\Path\To\AllUserData.csv -NoTypeInformation 

這使得一個散列表從用戶ID索引。它用來自第一個CSV文件的數據填充它。然後,每增加一個,它就會檢查第一個CSV和當前數據的屬性差異,將缺失的屬性添加到主散列表中的所有項目,然後按條目進入,如果用戶不在它添加它們的主要哈希表,如果它們是那麼它填補它可以爲其屬性的任何空白。

編輯:好的,所以你似乎有-notin運營商的問題。最可能的原因是PowerShell的舊版本。我的第一個建議是更新到v3或v4的PowerShell,但我知道這並不總是一個選項,所以爲了使這個更向下兼容,我已經對腳本進行了一些編輯,以使其適用於您...我希望。我用3個CSV文件測試了上面的腳本(在第1行更新了路徑,並且我註釋了最後一行,因爲我不想用更多的文件亂丟我的硬盤),並且每個CSV文件都有UserID字段,每個有2到4個條目,它的工作和我預期的完全一樣。無論如何,編輯的腳本是:

$CSVList = 'C:\Path\To\Users1.csv','C:\Path\To\Users2.csv','C:\Path\To\Users3.csv','C:\Path\To\Users4.csv','C:\Path\To\Users5.csv' 
$PrimaryTable = @{} 
Import-CSV $CSVList[0] | %{$PrimaryTable.Add($_.UserID,$_)} 
$PrimaryKeys = $PrimaryTable.Values[0] | Get-Member -MemberType Properties | Select -ExpandProperty Name 
ForEach($CSVFile in ($CSVList|Select -Skip 1)){ 
    $Users = Import-CSV $CSVFile 
    $Keys = $Users[0] | Get-Member -MemberType Properties | Select -ExpandProperty Name 
    $KeysToAdd = @{} 
    $Keys|?{$PrimaryKeys -notcontains $_}|%{$KeysToAdd.Add($_,"")} 
    $PrimaryTable.Values|%{$_|Add-Member -NotePropertyMembers $KeysToAdd} 
    ForEach($User in $Users){ 
     If(!($User.UserID -in $PrimaryTable.Keys)){ 
      $PrimaryKeys | ?{$Keys -notcontains $_} | %{add-member -InputObject $User -NotePropertyName $_ -NotePropertyValue ""} 
      $PrimaryTable.Add($User.UserID,$User) 
     }Else{ 
      $Keys | ?{[string]::IsNullOrWhiteSpace($PrimaryTable.($User.UserID).$_)} | %{$PrimaryTable.($User.UserID).$_ = $User.$_} 
     } 
    } 
    $PrimaryKeys = $PrimaryTable.Values[0] | Get-Member -MemberType Properties | Select -ExpandProperty Name 
} 

$PrimaryTable.Values|Export-CSV C:\Path\To\AllUserData.csv -NoTypeInformation 

這應該做你想做的,並應該在舊版本的PowerShell中工作。讓我知道你是否有錯誤。雖然如此,我的建議是如果您正在運行v2,請更新PowerShell。從長遠來看,你會比開展工作更快樂。

+0

這聽起來像它正是我需要的!但是,當我更新路徑並運行它時,出現以下錯誤: 您必須在' - '運算符的右側提供一個值表達式。 At:9 char:17 + $ Keys |?{$ _ - <<<< notin $ PrimaryKeys} |%{$ KeysToAdd.Add($ _,「」)} + CategoryInfo:ParserError:(:) [ ],ParseException + FullyQualifiedErrorId:ExpectedValueExpression – Benjoshyo

+0

嗯,我完全照原樣複製並粘貼它,在第一行更新路徑,註釋掉最後一行,因爲我不想輸出,並且運行它,它是用3個用於測試的簡短CSV文件(每個文件都有UserID字段,以及2到4個要解析的記錄)應該是什麼樣的。 **您使用的是什麼版本的PowerShell?**您是否使用PS v2?直到第3版,我認爲'-in'和'-notin'運算符才被引入。 – TheMadTechnician

+0

好吧,我花了一分鐘才明白髮生了什麼事。 -in和-notin不在Powershell 2.0中。一旦我更新Powershell,它就可以正常工作。非常感謝! – Benjoshyo

1

這裏是一個函數,可以用來按某個鍵對數據進行分組。如果某些組將有多個不同的值對於某些屬性,然後生成的對象將具有陣列該資源的所有值:

function Group-Data { 
    param(
     [object[]]$Property 
    ) 
    $AllProperties=[ordered]@{} 
    @(
     $input|Group-Object $Property|ForEach-Object { 
      $_.Group|ForEach-Object {[email protected]{}} { 
       $_.PSObject.Properties|Where-Object Value|ForEach-Object { 
        if($Properties[$_.Name]){ 
         if($Properties[$_.Name]-notcontains$_.Value){ 
          $Properties[$_.Name][email protected]($Properties[$_.Name];$_.Value) 
         } 
        }else{ 
         $Properties[$_.Name]=$_.Value 
         $AllProperties[$_.Name]=$null 
        } 
       } 
      } {[PSCustomObject]$Properties} 
     } 
    )|Select-Object @($AllProperties.Keys) 
} 

這裏是一個函數,它連接在陣列性能。您需要使用它,因爲Export-Csv不能正確處理屬性中的數組。

filter Join-Array { 
    param(
     [string]$Separator=', ' 
    ) 
    $_.PSObject.Properties|Where-Object Value -is Array|ForEach-Object { 
     $_.Value=$_.Value-join$Separator 
    } 
    $_ 
} 

而且你可以用這種方式:

Import-Csv File1.csv,File2.csv,File3.csv|Group-Data username|Join-Array|Export-Csv Result.csv 
0

數據管理可能是骯髒的,尤其是當你繼承一個爛攤子,這是大部分時間。

幫助您管理數據的最佳工具之一是數據庫管理系統,也就是DBMS。但是,這可能會在你的情況下過度。您可能只需要執行一次此操作,直到您將所有凌亂的繼承數據保存在一個整齊的CSV文件中,並保持最新狀態。在這種情況下,一個完整的DBMS的學習曲線可能不值得。

有三個關係運算符爲關係數據庫提供了在檢索時處理數據的大量功能。這些操作符是限制(以前稱爲select),項目和連接。如果你可以在PS中模擬這三個操作符,那麼你可以在不用調用DBMS的情況下在PS中清理你的數據。

PS已經有一個很好的運營商,做什麼限制。它是地方對象。

PS已經有了一個很好的操作員來完成項目的工作。它是組對象。

關係連接是它變得混亂的地方。據我所知,PS中沒有連接對象。但是Bacon Bits提供了Join-Object博客文章的鏈接,如果您想自行創建連接對象函數,這看起來正是您所需要的。謝謝,培根。一些博客文章是激勵人心的,解釋了爲什麼分解(分割)表有時是一件好事,然後激發連接對象以便在所有數據都在一個地方使用。如果你是一個SQL騎師,你已經知道這些東西。但學習如何在PS中做到這一點很棒。

+0

哈哈,你的第一句話真是太棒了! –

+1

那麼,我們很少清理我們繼任者的穀倉,特別是如果我們在多年的忠誠服務後才被解僱。 –