質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.81%

VBA コードのインデントについて

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,749

rebell

score 17

VBA応用(ADOでデータを取得する。)

上記URLのサイトを見てVBAの学習をしております。
以前はわからないコードについて質問させていただきました。

ソースレビューを受け手直しをしたのですがまだ見づらいと思っています。

誰が見ても見やすくするにはどうすればいいか教えてくださると助かります。

言語はjavaが使えます

よろしくお願いします。

Option Explicit

'スコープがPrivateになっている定数

Private Const g_cnsTitle = "ADOによるMDBデータ取得"
'MicrosoftのOLEDBを使うことを宣言
Private Const g_cnsAdoConnectString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source='"
'Accessデーターベースのファイル名?
Private Const g_cnsMdbName = "SampleCorp1.mdb"

Public Sub GetMDBDateByADO()

        '変数を定義

        Dim objFso As FileSystemObject                                       ' FileSystemObject
        Dim dbCon As ADODB.Connection                                   ' ADODB.Connection
        Dim dbRes As ADODB.Recordset                                      ' ADODB.Recordset
        Dim objSh As Worksheet                                                 ' Excel.Worksheet
        Dim strFilename As String                                               ' フルパスファイル名
        Dim strConnection As String                                           ' 接続文字列
        Dim strSQL As String                                                      ' SQL文編集WORK
        Dim strToday As String                                                   ' SQL文本日編集WORK
        Dim lngRow As Long                                                       ' 行INDEX
        Dim lngCol As Long                                                         ' 列INDEX

        'データベースのあるファイルのパス

        Set objFso = New FileSystemObject
        strFilename = objFso.BuildPath(ThisWorkbook.Path, g_cnsMdbName)  '
        Set objFso = Nothing    'オブジェクトへの参照を解除

        '接続文字列の編集
        strConnection = g_cnsAdoConnectString & strFilename & "';"

        'データベースへの接続
        Set dbCon = New ADODB.Connection
        dbCon.Open strConnection

        'クライアントカーソル設定
        dbCon.CursorLocation = adUseClient 'カーソルをクライアント側に持つか、サーバ側(例:Access)に持つかの設定 mdbはどちらにも持たない?

        '参照SQL文
        strToday = "#" & Format(Date, "yyyy-mm-dd") & "#"              '変換?

        strSQL = "SELECT H.[BUSYO_CD]"                                           ' (00)部署コード
        strSQL = strSQL & " , B.[BUSYO_NM]"                                        ' (01)部署名
        strSQL = strSQL & " , H.[YAKU_CD]"                                           ' (02)役職コード
        strSQL = strSQL & " , Y.[YAKU_NM]"                                           ' (03)役職名
        strSQL = strSQL & " , H.[SCD]"                                                    ' (04)社員コード
        strSQL = strSQL & " , S.[KANJI_SEI]+S.[KANJI_MEI]"                 ' (05)氏名(漢字)
        strSQL = strSQL & " , S.[KANA_SEI]+S.[KANA_MEI]"                  ' (06)氏名(カナ)
        strSQL = strSQL & " , S.[NYUSYA_YMD]"                                      ' (07)入社日
        strSQL = strSQL & " , S.[TAISYOKU_YMD]"                                   ' (08)退職日

        strSQL = strSQL & " FROM ((([MST_HAIZOKU] AS H"                                                                       '取得したいテーブルを指定
        strSQL = strSQL & " INNER JOIN [MST_SYAIN] AS S ON H.[SCD]=S.[SCD])"                                  'テーブルを内部結合
        strSQL = strSQL & " LEFT OUTER JOIN [MST_BUSYO] AS B ON H.[BUSYO_CD]=B.[BUSYO_CD])"  '外部結合
        strSQL = strSQL & " LEFT OUTER JOIN [MST_YAKU] AS Y ON H.[YAKU_CD]=Y.[YAKU_CD])"         '外部結合
        strSQL = strSQL & " WHERE S.[NYUSYA_YMD]<=" & strToday                                                          '入社日と本日日付を比較・制限して検索
        strSQL = strSQL & " AND (S.[TAISYOKU_YMD] IS NULL OR S.[TAISYOKU_YMD]>" & strToday & ")"  '
        strSQL = strSQL & " ORDER BY H.[BUSYO_CD],H.[YAKU_CD],H.[SCD];"                                             'クエリの結果を並べ替えする

        '参照SQL文の発行
        Set dbRes = New ADODB.Recordset
        dbRes.Open strSQL, dbCon, adOpenKeysetm, adLockReadOnly  'Openステートメント   ファイル開く

        '画面描画更新停止 描画を停止し処理を高速化
        Call GP_StopSCUPD '標準モジュール 「ZZZ_Module」内の「GP_StopSCUPD」プロシージャを呼び出し

        'シートの初期化
        Set objSh = ThisWorkbook.Worksheets(1)
        With objSh
                If .FilterMode Then .ShowAllData
                .Rows("2:" & .Rows.Count).ClearContents
                IngRow = 1

                '先頭レコードからEOFまで繰り返す End of Fileの略
                Do Until dbRes.EOF

                '行を加算
                IngRow = IngRow + 1

        '全列をシートに展開
        For IngCol = 0 To 8
                .Cells(IngRow, IngCol + 1).Value = dbRes.Fields(lngCol).Value
                Next IngCol
                '次のレコードに移る
                dbRes.MoveNext
        Loop

        End With

    ' レコードセット、データベースを閉じる
        dbRes.Close
        Set dbRes = Nothing
        dbCon.Close
        Set dbCon = Nothing

        ' 画面描画更新復帰
        Call GP_StartSCUPD

End Sub
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

一般的には、構造を持った文の開始行と、その終了の行は同じインデントで、その中味は1段下げます。

    With objSh
        If .FilterMode Then .ShowAllData
        .Rows("2:" & .Rows.Count).ClearContents
        IngRow = 1
        Do Until dbRes.EOF
            IngRow = IngRow + 1

            '全列をシートに展開
            For IngCol = 0 To 8
                .Cells(IngRow, IngCol + 1).Value = dbRes.Fields(lngCol).Value
            Next IngCol
            dbRes.MoveNext
        Loop
    End With


あとは、継続行のインデントは臨機応変でしょうか。

また、逐語的なコメントは書かないのが普通です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/31 16:51

    SQLを継続行で記述すると途中にコメントが付けられないので、個人的にはお勧めしません。

    キャンセル

  • 2018/10/31 16:56

    @sazi  継続行を回避した場合長くなってしまったSQLはどう成形してあげるのが見る人に取って優しいですか?

    キャンセル

  • 2018/10/31 17:03 編集

    ベースになるものをSQL単独で成形して、A5:SQLの「ソース文字列生成」でできたものを貼り付けしています。
    SQL単独での見易さも同じで、ブロックがインデントで揃えられていることですね。

    キャンセル

+2

ざっと見た感じでは綺麗に書けていると思いますよ。
2点気になったところ。
シートの初期化処理のWith内のインデントがずれているのはコピペミスでしょうか?
あと8タブになっているのもコピペミスでしょうか?
ミスでないなら4タブにしたほうがよいかと。

可読性の良し悪しを見てもらいたいなら、VBE上とまったく同じ状態で掲載されているか確認してくださいね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/31 16:45

    ありがとうございます。
    インデント自分で入れていたのでオプションを見てみることにします。

    キャンセル

  • 2018/10/31 16:58

    インデントによってコメントが見切れたりするのが嫌で、2タブにしちゃってます、私。

    キャンセル

  • 2018/11/01 08:25

    さすがに2タブだと詰まりすぎて私はダメですわ。
    長年4タブです。

    キャンセル

+2

VBA初心者としては上出来だと思いますよ!
コメントもVBAの界隈ではこの程度でちょうどいいんじゃないかと。

では、上級者への道として幾つか補足を。

●シートオブジェクト
「Set objSh = ThisWorkbook.Worksheets(1)」で、
Worksheet型の変数にセットしているのはOKですが、
自分のブックであれば、変数にセットせずに使えますよ~

VBE画面でモジュールの上に「Sheet1」とか見えてると思いますが、
これはシート自体のオブジェクト名で、
プロパティで「Sheet_Main」等と変えることができ、
コードを書く時に直接「Sheet_Main.Cells(1,2)」等と書けるので、
変数が不要になります。
※確か、Nothing しちゃうとバグると思うので、そこだけ気を付けてください。

●行、列の定義
「.Rows("2:" & .Rows.Count)」や、
「For IngCol = 0 To 8 」で、
直接「2」等と番号を使ってますが、
別途定義しないと、行・列の変化があった時に
コードの調整に非常に多くの時間を割くことになってしまいます。

1つ目の方法は、Constを使って定義する方法があります。

しかし、↓のように定義量が多いと、やはり変化があった時に調整が面倒です。

Public Const Col_Code   As Long = 1
'←ここにNo等、新しい列を追加するとなると、↓の定義を+1等と変えなきゃいけなくなる。。。
Public Const Col_Name   As Long = 2 
Public Const Col_Address   As Long = 3
Public Const Col_xxx4   As Long = 4
Public Const Col_xxx5   As Long = 5
Public Const Col_xxx6   As Long = 6
Public Const Col_xxx7   As Long = 7
Public Const Col_xxx8   As Long = 8

2つ目の方法は、Enumを使って定義する方法があります。
自分は、こちらをオススメします。

Public Enum E_Col_Main
    Data_S = 2  'データ開始列
        Type_ = E_Col_Main.Data_S
        Module
        Equal
        UpDate
        UserName
        UserComment
        UpCount
    Data_E = E_Col_Main.UpCount 'データ終了列
End Enum


Enumは=2等と定義した以降は、自動で1つずつインクリメントしてくれるので、
開始番号だけ定義すれば、以降は番号指定が不要になります。

また、列を途中で追加したい、列を入れ替えたい、という変化に対しても、
定義を1つ追加する、順番を入れ替える、という調整で済むようになります。

上記の例で「Data_S」「Data_E」と定義しているのは、
データの開始列、終了列、を定義していて、
「「For IngCol = 0 To 8 」のように
「全列に対して処理する」という場合に使用する為です。

変数名をみれば、全列に対して処理しようとしているのか、
それとも一部に対して処理したいのか、
という事が分かりやすくなると思います。

※開始列、最終列に定義を追加する場合には、
定義を修正する必要があるので、そこだけは気を付けてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/01 09:39

    余談ながら、参考書としては「VBAを実務で使い倒す技術」をおすすめしています。
    プログラマ寄りに書いている内容なので、
    色々と役に立つと思います。

    余談ついでに、自分は、変数は使用する直前で宣言する派です。
    その方が開発やデバッグがしやすくなると思っています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.81%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る