이 (단순화 된) 코드 청크를 사용하여 BCP로 SQL Server에서 테이블 집합을 추출하고 있습니다.
$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
}
훌륭하게 작동하지만 이제 일부 테이블은 뷰를 통해 추출해야하고 일부는 추출하지 않습니다. 따라서 다음과 같은 데이터 구조가 필요합니다.
"Page" "vExtractPage"
, "ChecklistItemCategory" "ChecklistItemCategory"
, "ChecklistItem" "vExtractChecklistItem"
해시를보고 있었지만 해시를 반복하는 방법에 대해서는 아무것도 찾지 못했습니다. 여기서 옳은 일은 무엇일까요? 아마도 배열을 사용하지만 두 값을 공백으로 구분하여 사용합니까?
아니면 분명한 것을 놓치고 있습니까?
답변
Christian의 대답은 잘 작동하며 GetEnumerator
방법을 사용하여 각 해시 테이블 항목을 반복하는 방법을 보여줍니다 . keys
속성 을 사용하여 반복 할 수도 있습니다. 다음은 방법의 예입니다.
$hash = @{
a = 1
b = 2
c = 3
}
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }
산출:
key = c , value = 3
key = a , value = 1
key = b , value = 2
답변
속기는 스크립트에 선호되지 않습니다. 읽기 어렵습니다. % {} 연산자는 속기로 간주됩니다. 가독성과 재사용 성을 위해 스크립트에서 수행하는 방법은 다음과 같습니다.
변수 설정
PS> $hash = @{
a = 1
b = 2
c = 3
}
PS> $hash
Name Value
---- -----
c 3
b 2
a 1
옵션 1 : GetEnumerator ()
참고 : 개인 취향; 구문이 읽기 쉽습니다.
GetEnumerator () 메서드는 다음과 같이 수행됩니다.
foreach ($h in $hash.GetEnumerator()) {
Write-Host "$($h.Name): $($h.Value)"
}
산출:
c: 3
b: 2
a: 1
옵션 2 : 키
Keys 메서드는 다음과 같이 수행됩니다.
foreach ($h in $hash.Keys) {
Write-Host "${h}: $($hash.Item($h))"
}
산출:
c: 3
b: 2
a: 1
추가 정보
해시 테이블을 신중하게 정렬하십시오 …
Sort-Object 는 배열로 변경할 수 있습니다.
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
답변
변수 없이도이 작업을 수행 할 수 있습니다.
@{
'foo' = 222
'bar' = 333
'baz' = 444
'qux' = 555
} | % getEnumerator | % {
$_.key
$_.value
}
답변
해시를 반복하는 방법 :
$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"}
$Q.GETENUMERATOR() | % { $_.VALUE }
1
3
2
$Q.GETENUMERATOR() | % { $_.key }
ONE
THREE
TWO
답변
다음은 값을 얻기 위해 키를 해시 테이블에 대한 인덱스로 사용하는 또 다른 빠른 방법입니다.
$hash = @{
'a' = 1;
'b' = 2;
'c' = 3
};
foreach($key in $hash.keys) {
Write-Host ("Key = " + $key + " and Value = " + $hash[$key]);
}
답변
foreach (PowerShell 5에서 테스트 됨)의 해시 테이블을 참조 할 필요가 없기 때문에 파이프 라인이있는 열거 자 메서드에서이 변형을 선호합니다.
$hash = @{
'a' = 3
'b' = 2
'c' = 1
}
$hash.getEnumerator() | foreach {
Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}
산출:
Key = c and Value = 1
Key = b and Value = 2
Key = a and Value = 3
이제 이것은 의도적으로 값에 따라 정렬되지 않았으며 열거자는 단순히 개체를 역순으로 반환합니다.
그러나 이것은 파이프 라인이므로 이제 열거 자에서받은 개체를 값으로 정렬 할 수 있습니다.
$hash.getEnumerator() | sort-object -Property value -Desc | foreach {
Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}
산출:
Key = a and Value = 3
Key = b and Value = 2
Key = c and Value = 1
답변
PowerShell v3를 사용하는 경우 해시 테이블 대신 JSON을 사용하고 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
}