2012-01-26 21 views
58

Tôi đang sử dụng đoạn mã (đơn giản) này để trích xuất một tập hợp các bảng từ SQL Server với bcp.Lặp qua một băm hoặc sử dụng một mảng trong PowerShell?

$OutputDirectory = "c:\junk\" 
$ServerOption = "-SServerName" 
$TargetDatabase = "Content.dbo." 

$ExtractTables = @(
    "Page" 
    , "ChecklistItemCategory" 
    , "ChecklistItem" 
    ) 

for ($i=0; $i -le $ExtractTables.Length – 1; $i++) { 
    $InputFullTableName = "$TargetDatabase$($ExtractTables[$i])" 
    $OutputFullFileName = "$OutputDirectory$($ExtractTables[$i])" 
    bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption 
} 

Nó hoạt động tốt, nhưng bây giờ một số bảng cần được trích xuất qua chế độ xem và một số thì không. Vì vậy, tôi cần cấu trúc dữ liệu giống như sau:

"Page"      "vExtractPage" 
, "ChecklistItemCategory" "ChecklistItemCategory" 
, "ChecklistItem"   "vExtractChecklistItem" 

Tôi đã xem xét băm, nhưng tôi không tìm thấy bất kỳ thứ gì về cách lặp qua băm. Điều gì sẽ là điều đúng để làm ở đây? Có lẽ chỉ cần sử dụng một mảng, nhưng với cả hai giá trị, cách nhau bằng dấu cách?

Hoặc tôi có thiếu điều gì đó hiển nhiên không?

Trả lời

72

câu trả lời của Christian hoạt động tốt và cho thấy làm thế nào bạn có thể lặp qua từng mục bảng băm sử dụng phương pháp GetEnumerator. Bạn cũng có thể lặp qua sử dụng thuộc tính keys. Dưới đây là một ví dụ như thế nào:

$hash = @{ 
    a = 1 
    b = 2 
    c = 3 
} 
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) } 

Output:

key = c , value = 3 
key = a , value = 1 
key = b , value = 2 
+0

Làm cách nào tôi có thể liệt kê băm theo thứ tự khác? Ví dụ. khi tôi muốn in nội dung của nó theo thứ tự tăng dần (ở đây là ... b ... c). Thậm chí có thể không? – LPrc

+0

Tại sao '$ hash.Item ($ _)' thay vì '$ hash [$ _]'? – alvarez

+1

@LPrc sử dụng phương pháp Sort-Object để thực hiện điều đó. Bài viết này làm một lời giải thích khá tốt về nó: https://technet.microsoft.com/en-us/library/ee692803.aspx – chazbot7

4

Về vòng lặp thông qua một băm:

$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"} 
$Q.GETENUMERATOR() | % { $_.VALUE } 
1 
3 
2 

$Q.GETENUMERATOR() | % { $_.key } 
ONE 
THREE 
TWO 
125

Shorthand không được ưa chuộng cho các kịch bản; nó ít dễ đọc hơn. Toán tử% {} được coi là viết tắt. Đây là cách nó nên được thực hiện trong một kịch bản để có thể đọc và tái sử dụng:

Cài Đặt Biến

PS> $hash = @{ 
    a = 1 
    b = 2 
    c = 3 
} 
PS> $hash 

Name       Value 
----       ----- 
c        3 
b        2 
a        1 

Lựa chọn 1: GetEnumerator()

Lưu ý: sở thích cá nhân; Cú pháp là dễ dàng hơn để đọc

Các GetEnumerator() phương pháp sẽ được thực hiện như:

foreach ($h in $hash.GetEnumerator()) { 
    Write-Host "$($h.Name): $($h.Value)" 
} 

Output:

c: 3 
b: 2 
a: 1 

Lựa chọn 2: Phím

Phương pháp Phím sẽ được thực hiện như được hiển thị:

foreach ($h in $hash.Keys) { 
    Write-Host "${h}: $($hash.Item($h))" 
} 

Output:

c: 3 
b: 2 
a: 1 

thông tin bổ sung

Hãy cẩn thận sắp xếp Hashtable của bạn ... Sort-Object có thể thay đổi nó thành một mảng:

PS> $hash.GetType() 

IsPublic IsSerial Name          BaseType 
-------- -------- ----          -------- 
True  True  Hashtable        System.Object 


PS> $hash = $hash.GetEnumerator() | Sort-Object Name 
PS> $hash.GetType() 

IsPublic IsSerial Name          BaseType 
-------- -------- ----          -------- 
True  True  Object[]         System.Array 
+3

như thế này nhiều hơn cho dễ đọc, đặc biệt là cho không dành các nhà phát triển powershell như tôi. – anIBMer

+1

Tôi đồng ý phương pháp này dễ đọc hơn và có thể tốt hơn cho việc viết kịch bản. – leinad13

+1

Dễ đọc, có một sự khác biệt giữa giải pháp của VertigoRay và giải pháp của Andy. % {} là một bí danh cho 'ForEach-Object', khác với câu lệnh' foreach' ở đây. 'ForEach-Object' sử dụng đường ống, có thể nhanh hơn nhiều nếu bạn đang làm việc với một đường ống. Câu lệnh 'foreach' không có; đó là một vòng lặp đơn giản. – JamesQMurphy

1

Nếu bạn đang sử dụng PowerShell v3, bạn có thể sử dụng JSON thay vì một Hashtable, và chuyển nó sang một đối tượng với Convert-FromJson:

@' 
[ 
    { 
     FileName = "Page"; 
     ObjectName = "vExtractPage"; 
    }, 
    { 
     ObjectName = "ChecklistItemCategory"; 
    }, 
    { 
     ObjectName = "ChecklistItem"; 
    }, 
] 
'@ | 
    Convert-FromJson | 
    ForEach-Object { 
     $InputFullTableName = '{0}{1}' -f $TargetDatabase,$_.ObjectName 

     # In strict mode, you can't reference a property that doesn't exist, 
     #so check if it has an explicit filename firest. 
     $outputFileName = $_.ObjectName 
     if($_ | Get-Member FileName) 
     { 
      $outputFileName = $_.FileName 
     } 
     $OutputFullFileName = Join-Path $OutputDirectory $outputFileName 

     bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption 
    } 
+0

n.b. lệnh là ConvertFrom-Json (và converse, ConvertTo-Json) - chỉ cần đổi vị trí dấu gạch ngang. – atmarx

4

Bạn cũng có thể làm điều này mà không có biến số

@{ 
    'foo' = 222 
    'bar' = 333 
    'baz' = 444 
    'qux' = 555 
} | % getEnumerator | % { 
    $_.key 
    $_.value 
} 
+0

Điều này cho tôi một "ForEach-Object: Không thể ràng buộc tham số 'Process'. Không thể chuyển đổi giá trị" getEnumerator "của loại" System.String "để gõ" System.Management.Automation.ScriptBlock " –

3

Đây là một cách nhanh chóng khác, chỉ sử dụng khóa làm chỉ mục vào bảng băm để lấy valu e:

$hash = @{ 
    'a' = 1; 
    'b' = 2; 
    'c' = 3 
}; 

foreach($key in $hash.keys) { 
    Write-Host ("Key = " + $key + " and Value = " + $hash[$key]); 
} 
Các vấn đề liên quan