2015年12月30日水曜日

ワークシートを明示しないRangeオブジェクトの参照先

プロシージャの中でワークシートを明示せずにRangeオブジェクトを使った場合、どのワークシートのRangeオブジェクトが参照されるかの実験。

Sheet1とSheet2の各々のセル 'A1' に '名前' という名前のNameを作る。


Sheet1.Names.Add Sheet1!名前, =Sheet1!$A$1
Sheet2.Names.Add Sheet2!名前, =Sheet2!$A$1


そして、Sheet1モジュールに下記のプロシージャを書き、実行する。


Public Sub TestSheet1Proc()

    ' (1)
    Debug.Print Range("A1").Parent.Name
    ' (2)
    Debug.Print Cells(1, 1).Parent.Name
    ' (3)
    Debug.Print Range("名前").Parent.Name

End Sub


イミディエイト・ウインドに 'Sheet1' が3行出力される。
Sheet2モジュールのプロシージャから Sheet1.TestSheet1Proc を呼び出して実行したらどうなるか?
結果は変わらず、'Sheet1' が3行出力される。
ThisWorkbookモジュールからでも同様。

TestSheet1Proc を標準モジュール又はThisWorkBookモジュールにコピペして実行した場合、どうなるか?
結果はアクティブ・シートが何かで異なる。

Sheet1がアクティブの場合、'Sheet1' が3行出力される。
Sheet2がアクティブの場合、'Sheet2' が3行出力される。
Sheet3がアクティブの場合、'Sheet3' が2行出力されるが、(3)でエラーとなる。

Sheet3に '名前' という名前のNameを作ればこのエラーは出なくなる。

シート・モジュール内でワークシートを明示せずにRangeオブジェクトを使用した場合、常にそのシートのRange(セル)が参照される。

標準モジュールやThisWorkbookモジュールでワークシートを明示せずにRangeオブジェクトを使用した場合、アクティブ・シートのRange(セル)が参照される。



2015年12月26日土曜日

Connection を閉じて、Recordset を使う

ADOについて、Connection を閉じて、Recordset を使う方法。
データベース接続を速やかに切断することで、データベースの負荷を軽減できる。

マイクロソフトの「ADO プログラマーズ リファレンス」のCloseメソッドの説明によると、

◆Close により関連する全てのシステムリソースが解放される。
◆オブジェクトはメモリからは削除されず、プロパティ設定を変更してもう一度開くことができる。
◆メモリからオブジェクトを完全に削除するには、オブジェクト変数を Nothing に設定する。

とのこと。


Sub TestUnconnectedRs()

    Dim cn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    cn.Open connectionString

    ' ↓ここがポイント(1)
    rs.CursorLocation = adUseClient

    rs.Open sqlString, cn, adOpenKeyset, adLockOptimistic

    ' ↓ここがポイント(2)
    Set rs.ActiveConnection = Nothing
    ' ※cn.Close ではエラーとなる。rsもCloseされてしまう。
    ' ※Set cn = Nothing はOK。

    Do Until rs.EOF
        Debug.Print rs.Fields(0).Value
        rs.MoveNext
    Loop
    rs.Close

End Sub


ポイント(1) CursorLocation に 'adUseClient' を設定しないとエラーとなる。
ポイント(2) cn.Close では「関連する全てのシステムリソースが解放される」ので、実行と同時に rs も Close されてしまい、エラーとなる。Nothing の場合、cn だけが閉じられ、rs はメモリ上に残る。cn を再び使う場合は、Newする必要がある。




2013年12月23日月曜日

Split関数から配列に代入

Split関数から要素数未設定の配列に代入できる。

◆Split関数

 引数1  区切り文字で区切られたテキスト。
 引数2  区切り文字の指定。
 戻り値  引数1の文字列が格納された配列。

◆例

Sub x()
  
    Dim stg() As String
    Dim i As Long
  
    stg = Split("子,丑,寅,卯,辰,巳,午,未,申,酉,戌,亥", ",")
  
    For i = 0 To UBound(stg)
        Debug.Print stg(i)
    Next
  
End Sub


変数stgの要素数をReDimで設定せずに代入可能。
stgの宣言文でstgの後に()がないとエラーとなる。
stgをVariant型にした場合、変数名の後に()があるとエラーとなる。