ラベル PowerShell の投稿を表示しています。 すべての投稿を表示
ラベル PowerShell の投稿を表示しています。 すべての投稿を表示

2019年1月20日日曜日

PowerShellのループ処理

PowerShellを使ったループ処理のサンプルを作成する。
お題:任意のディレクトリ内のファイルについて列挙する。
※SQL Serverのインストールディレクトリ内の「DATA」フォルダを参照するサンプルを作成する。

enter image description here


まずはディレクトリを移動
PS C:\Users\kimiyuki> cd "C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA"

PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA> 

ディレクトリ内のファイルの列挙
・Get-ChildItemでディレクトリ以下のファイルを列挙出来る。
 -Includeオプションで拡張子を指定している。
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA> 
Get-ChildItem -Recurse -File -Include *.mdf


    ディレクトリ: C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA


Mode                LastWriteTime     Length Name                                                                                                                                                                                 
----                -------------     ------ ----                                                                                                                                                                                 
-a---        2019/01/03     20:55  130088960 AdventureWorksDW2012.mdf                                                                                                                                                             
-a---        2019/01/03     20:55   23003136 AdventureWorksLT2012.mdf                                                                                                                                                             
-a---        2019/01/03     20:55    5111808 master.mdf                                                                                                                                                                           
-a---        2019/01/03     20:55    4259840 model.mdf                                                                                                                                                                            
-a---        2019/01/03     20:55   17498112 MSDBData.mdf                                                                                                                                                                         
-a---        2019/01/20      5:10  148897792 MyStockDB.mdf                                                                                                                                                                        
-a---        2019/01/05      2:10   12582912 SalesDB.mdf                                                                                                                                                                          
-a---        2019/01/03     20:55   41943040 SSISDB.mdf                                                                                                                                                                           
-a---        2019/01/03     21:01    8388608 tempdb.mdf                                                                                                                                                                           
-a---        2019/01/03     20:55   14680064 TestDB.mdf       
※列挙するだけならGet-ChildItemコマンドで十分であるが、
ループ毎に何らかの処理をしたい場合は不十分…

foreachによるループ処理
・Get-ChildItemの結果を$array にObject型の配列として格納する。
・LastWriteTimeはDateTime型なのでToStringでフォーマットを指定できる。
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA> 
$array = (Get-ChildItem -Recurse -File -Include *.mdf )
foreach($a in $array) 
{
    echo $a.LastWriteTime.ToString("yyyyMMdd_HHmmss")  
} 
    
20190103_205520 
20190103_205518 
20190103_205524 
20190103_205522 
20190103_205522 
20190120_051006 
20190105_021043 
20190103_205517 
20190103_210146 
20190103_205518 
※foreachのループ処理部分で個別のロジックの記述が可能。
感覚的にはC#のループ処理と同じイメージ。


foreach-objectによるループ処理
foreachの例と同様にGet-ChildItemの結果を加工する。
PS C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEVA\MSSQL\DATA> 
Get-ChildItem -Recurse -File -Include *.mdf | ForEach-Object -Begin{$array= @();} -Process{$array += $_.LastWriteTime.ToString("yyyyMMdd_HHmmss")} -End{$array}

20190103_205520
20190103_205518
20190103_205524
20190103_205522
20190103_205522
20190120_051006
20190105_021043
20190103_205517
20190103_210146
20190103_205518
※ForEach-Object コマンドレットでは、パイプに渡して処理を書くので1行で収まっている(可読性は悪い気が…)
-Beginオプション:前処理を記述(データを格納する配列を宣言)
-Processオプション:処理内容を記述(配列にデータを格納)
 「$_」で元のデータにアクセスできる
-Endオプション:後処理(結果の表示)


まとめ

色々調べると、foreachステートメントよりforeach-objectコマンドレットの方がメモリ量が少なくて済むそうなので処理の高速化が期待できる。
でも、使ってみるとforeachステートメントの方がC#等のループ処理に近い感覚で記述できるので分かりやすい気がします。
この辺の感じは未だにラムダ式に慣れずクエリ式でLinqを書いている感覚に近いものがあります…

参考

Powershellのforeach(ForEach-Object)の使い方

【ForEach-Object】PowerShellでパイプからforeachループするテクニック

PowerShellの落とし穴!ForEach-Objectとforeachは違う?

PowerShellのGet-ChildItemコマンドレットでファイル名の一覧を取得する(応用編)


2018年12月31日月曜日

SQL Server の Import Export Wizard によるデータのExport

SQL Server のBCPコマンドによるデータエクスポート の投稿でBCPコマンドを使ってTableデータをファイルに書き出す方法を説明している。
今回は、SQL Server のタスクに標準で備わっているデータエクスポートの機能を使ってTableデータをファイルに出力してみる。

環境

  • DB: SQL Server 2012 SP4 (11.0.7001.0 (X64)) Evaluation or Express
  • データソース: AdventureWorksLT2012
  • データ保存先:ローカル ファイル(テキスト ファイル)
AdventureWorksLT2012 の SalesLT.Customer のデータをファイルに出力する。

Import/Export WizardによるデータExport

SSMSを起動しオブジェクトエクスプローラーからAdventureWorksLT2012を右クリック→タスク→データのエクスポート を選択する。

enter image description here



SQL Server インポートおよびエクスポート ウィザード
・ようこそ

enter image description here


・データソースの選択
認証:Windows認証
データベース:AdventureWorksLT2012

enter image description here


・変換先の選択
※データベース:AdventureWorksLT2012 の照合順序(SQL_Latin1_General_CP1_CI_AS) に対応したコードページを選択すること!! (コードページの選択を誤ると実行時にエラーになる)

コードページの例(抜粋)
Identifier .NET Name Additional information
1252 windows-1252 ANSI Latin 1; Western European (Windows)
932 shift_jis ANSI/OEM Japanese; Japanese (Shift-JIS)
65001 utf-8 Unicode (UTF-8)
51932 euc-jp EUC Japanese

※ファイル名に出力先のファイルのフルパスを設定する。
ディレクトリを予め作成していること。

enter image description here


・テーブルコピーまたはクエリの指定

enter image description here


・フラットファイル変換先の構成
※元データとして SalesLT.Customer テーブルを選択する。
区切りは規定値を使用する。

enter image description here


・パッケージの保存および実行
設定内容をすぐに実行するか、SSISパッケージとして再利用可能なように保存するかを選択できる。
→ SSISパッケージとして保存できるのは、Evaluation または Standard以上の商用ライセンスの場合のみ。
今は「すぐに実行」を選択する。
※以下図は、Evaluation または Standard以上の商用ライセンスの場合

enter image description here


※Developer または Express等の無償ライセンスの場合

enter image description here


・ウィザードの完了
設定内容の概要を確認します。

enter image description here


・操作の完了
エラー無く処理が完了すると下図のような結果が表示されます。

enter image description here


・出力結果

enter image description here

コードページの選択エラー

上記例では元データとして AdventureWorksLT2012 を使用している。
AdventureWorksLT2012 の照合順序は SQL_Latin1_General_CP1_CI_AS であるため、対応したコードページとして「1252 (ANSI - ラテンI)」を選択しなければならないと説明している。
ここでは敢えてコードページを「932 (ANSI/OEM - 日本語 Shift-JIS)」に設定した場合で実行してみる。

・コードページを「932 (ANSI/OEM - 日本語 Shift-JIS)」に設定

enter image description here


・実行エラーが発生

enter image description here


・エラーメッセージ
→ コードページについて警告されている。

enter image description here


このように元のデータの照合順序と対応しないコードページを設定するとエラーとなり実行出来ない。


SSISパッケージの作成と再利用

上記事例ではExport処理を実施してしまうと操作を再利用することが出来ない。(もう一度ウィザードを始めから設定することになる)
Evaluation または Standard 以上の商用ライセンスの場合はSSISパッケージをファイルとして保存することが出来、コマンドプロンプトまたはPowerShellから実行することが出来る。
今回はEvaluation Editionの環境でSSISパッケージの保存とPowerShellによる実行を試してみる。

・SSISパッケージの保存設定1
保存先としてSQL Server 又はファイルシステムが選択できるが、今回はファイルシステムを選択。
保護レベルとパスワードを設定。

enter image description here


・SSISパッケージの保存設定2
保存先のディレクトリを設定する

enter image description here


・ウィザードの完了
設定内容の概要を確認します。

enter image description here


・操作の完了
エラー無く処理が完了すると下図のような結果が表示されます。

enter image description here


・SSISパッケージの実行
SSISパッケージの実行にはコマンドプロンプトまたはPowerShellでDTEXECコマンドを使用します。
DTEXEC /f “[SSISパッケージの保存パス(.dtsx)]” /Decrypt [パスワード]
※SQL Server をバージョンアップした環境で上記DTEXECコマンドを実行すると以下のエラーが発生します。
エラー: 2018-12-31 05:50:33.59 コード: 0xC0016020 ソース: 説明: エラー
0xC001700A “パッケージに含まれるバージョン番号が無効です。バージョン番号を現在のバージョン番号より大きくすることはできません。”
により、パッケージをバージョン 6 から 3 に移行できませんでした。
上記エラーはDTEXECコマンドに関連付けられているEXEの実体がSQL Server 2012ではない(古いVersion)になっていることが原因のようです。
レジストリを書き換えれば良さそうな気もしますが、SQL Server 2012に対応いたEXEを指定するようにコマンドを記載すれば動作します。

PS C:\Users\hoge> & "C:\Program Files\Microsoft SQL Server\110\DTS\Binn\DTExec.exe" /f  "C:\Temp\Export_Customer.dtsx" /Decrypt hogepin
Microsoft (R) SQL Server Execute Package Utility
Version 11.0.7001.0 for 64-bit
Copyright(C) Microsoft Corporation. All rights reserved.

開始: 5:54:24
進捗状況: 2018-12-3105:54:26.00
   ソース: データ フロー タスク 1
   検証しています: 0% の完了
進捗状況の終了

~

進捗状況: 2018-12-3105:54:26.59
   ソース: データ フロー タスク 1
   クリーンアップ: 100% の完了
進捗状況の終了
DTExec: パッケージの実行から返されました DTSER_SUCCESS (0)。
開始: 5:54:24
完了: 5:54:26
経過時間:  2.059 秒
※EXEのフルパスを指定する場合に「Program Files」のように間にスペースが入るパスを指定する場合は、パス名の前に「&」を追加すること。


まとめ

  • SSISを使ってデータをフラットファイルにExportする場合は、元データの照合順序と出力先のコードページの指定を正しく設定すること。
  • 商用ライセンスではSSISパッケージを保存することが出来る。
  • SSISパッケージを実行する場合は「DTEXEC」コマンドをPowerShell等で実行する。
  • SQL Server のVersionが複数インストールされている環境では、DTEXECコマンドの指定でEXEのフルパスを指定すること。

追記(12/31)
SSISパッケージの保存で「ファイルシステム」ではなく、「SQL Server」を選んだケースを試してみたが、
  • SSMSでIntegration Services にログインして「格納済のパッケージ」ディレクトリの「MSDB」の配下にSSISパッケージが格納されていることを確認。
  • 実行したがエラーとなる。エラー内容から、Edtionの権限が認められていない模様。実行時はEvaluation Edition のインスタンスであったが、同じ環境下にExpress Edition のインスタンスが構築されており、その辺の問題かと。

enter image description here

  • 上記のようにSSISパッケージをSQL Serverに保存したところ、以前の投稿で作成していた統合サービスカタログが初期化されてしまった…
    Import/Export Wizard で作成したSSISパッケージをSQL Serverに保存するのはやめた方が良さそう…

参考

Code Page Identifiers

DTExec.exe を使用してコマンド プロンプトから SSIS パッケージを実行する