goo blog サービス終了のお知らせ 

Re:SALOON & VBA

しばらくは、過去BBSの倉庫、および
作成した EXCEL VBA の置き場(公開)として

VBA 汎用SQL実行ツール

2016年01月29日 18時43分24秒 | EXCEL VBA
シートSQLに記入したSQLを実行して、先頭シートに検索結果を展開(表化)するツールを考えました。
ACCESS版 SQL実行(EXCEL VBA)の改良版(簡略化しました)です。
シンプルに考えると、
基本的にORACLE検索系のVBAで僕がしたいのは、
こういうことだったのだ・・・ということで。

**************************************************************************
Option Explicit

Declare Function SetCurrentDirectory Lib "kernel32" Alias _
        "SetCurrentDirectoryA" (ByVal CurrentDir As String) As Long

Sub SQL_RUN()
  Dim adoCn As ADODB.Connection: Set adoCn = New ADODB.Connection
  Dim adoRs As ADODB.Recordset: Set adoRs = New ADODB.Recordset
  Dim i   As Integer: i = 1
  Dim strSQL As String: strSQL = ""
' Dim strUID As String: strUID = "ADMINISTRATOR"         ' ユーザー
' Dim strPWD As String: strPWD = "ADMINPWD"            ' パスワード
' Dim strSID As String: strSID = "ORCL"             ' Service-Name
  Dim strDSN As String: strDSN = ThisWorkbook.Path & "\TEST.dsn" ' DSNファイル名
  On Error GoTo ErrHandler
  SetCurrentDirectory ThisWorkbook.Path
  Application.ScreenUpdating = False
' SQL読込み(SQLシート)
  Sheets("SQL").Visible = True
  Sheets("SQL").Select
  Do While Cells(i, 1) <> ""
   strSQL = strSQL + Cells(i, 1).Value
   i = i + 1
  Loop
  If strSQL = "" Then Exit Sub
  Sheets("SQL").Visible = False
  Sheets(1).Select
  Call BorderClear  ' 罫線クリア
' DB接続 環境により設定
' (TNSNames.ora)<== 参考
' adoCn.Open "Provider=MSDAORA;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=" & _
'       "(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))" & _
'       "(CONNECT_DATA=(SERVICE_NAME=" & strSID & ")));", strUID, strPWD
' (ODBC-ORACLE)<== 参考
' adoCn.Open "FileDSN=" & strDSN & ";UID=" & strUID & ";PWD=" & strPWD & ";"
' (ODBC-ACCESS)<== これでテストしている
  adoCn.Open "FileDSN=" & strDSN & ";"
' SQL実行
  adoRs.Open strSQL, adoCn, adOpenStatic, adLockReadOnly
' 見出しセット(未設定のとき)
  If Range("A1").Value = "" Then
   For i = adoRs.Fields.Count To 1 Step -1
     Cells(1, i).Value = adoRs.Fields(i - 1).Name
   Next i
  End If
' SQL検索結果セット
  Range("A2").CopyFromRecordset adoRs
' DB切断
  adoRs.Close
  adoCn.Close
  Set adoRs = Nothing
  Set adoCn = Nothing
  Call BorderSet   ' 罫線描画
  Call FormatSet   ' 書式設定(見出しセルに指定した書式を同列に設定する)
  RANGE("A2").select
  Application.ScreenUpdating = True
  Exit Sub
ErrHandler:
  If Err.Number = 3709 Then Exit Sub
  MsgBox Err.Description & " " & Err.Number
  Resume Next
End Sub

' 罫線クリア
Private Sub BorderClear()
  If Cells(2, 1).Value = "" Then Exit Sub
  Dim MaxRow As Long:  MaxRow = Range("A2").End(xlDown).Cells.Row
  Dim MaxCol As Integer: MaxCol = Range("A1").End(xlToRight).Cells.Column
  Range(Cells(2, 1), Cells(MaxRow, MaxCol)).Select
  Selection.Borders.LineStyle = xlNone
  Selection.ClearContents
End Sub

' 罫線描画
Private Sub BorderSet()
  If Cells(2, 1).Value = "" Then Exit Sub
  Dim MaxRow As Long:  MaxRow = Range("A2").End(xlDown).Cells.Row
  Dim MaxCol As Integer: MaxCol = Range("A1").End(xlToRight).Cells.Column
  Range(Cells(2, 1), Cells(MaxRow, MaxCol)).Select
  Selection.Borders.LineStyle = xlContinuous
End Sub

' 書式設定(見出しセルに指定した書式を同列に設定する)
Private Sub FormatSet()
  Dim i    As Integer: i = 1
  Dim strTEXT As String
  Do While Cells(1, i).Value <> ""
   If Cells(1, i).NumberFormatLocal <> "G/標準" And _
     Cells(1, i).NumberFormatLocal <> Cells(2, i).NumberFormatLocal Then
     strTEXT = Cells(1, i).NumberFormatLocal
     If strTEXT = "yyyy/mm/dd;@" Then
      Columns(i).Select
      Selection.HorizontalAlignment = xlCenter
      Selection.NumberFormatLocal = "yyyy/mm/dd;@"
      With Selection.FormatConditions
       .Delete
       .Add Type:=xlExpression, Formula1:="=AND(MONTH(RC[])>9,DAY(RC[])<10)"
       .Add Type:=xlExpression, Formula1:="=AND(MONTH(RC[])<10,DAY(RC[])>9)"
       .Add Type:=xlExpression, Formula1:="=AND(MONTH(RC[])<10,DAY(RC[])<10)"
       .Item(1).NumberFormat = "yyyy/mm/_0d;@"
       .Item(2).NumberFormat = "yyyy/_0m/dd;@"
       .Item(3).NumberFormat = "yyyy/_0m/_0d;@"
      End With
     Else
      Columns(i).Select
      Selection.NumberFormatLocal = strTEXT
     End If
   End If
   i = i + 1
  Loop
End Sub

' シート書出し
Sub SheetOut()
  Sheets(1).Select
  If Cells(2, 1).Value = "" Then
   MsgBox "このシートにはデータがありません!"
   Exit Sub
  End If
  Dim strFileName As String
  Dim i      As Integer
  SetCurrentDirectory ThisWorkbook.Path
  strFileName = ThisWorkbook.Path & "\" & Replace(ThisWorkbook.Name, "xlsm", "")
  If Dir(strFileName & ".xlsx") <> "" Then
   strFileName = strFileName & "_" & Replace(Time$, ":", "")
  End If
  Worksheets(1).Move
  For i = ActiveSheet.Shapes.Count To 1 Step -1
   If ActiveSheet.Shapes(i).Type = msoFormControl Then ActiveSheet.Shapes(i).Delete 'ボタンを削除
  Next i
  Call ListSet    ' テーブルスタイル設定
  ActiveWorkbook.Worksheets(1).Name = Date$
  Range("A2").Select
  ActiveWorkbook.SaveAs Filename:=strFileName & ".xlsx", FileFormat:=xlWorkbookDefault
  ThisWorkbook.Close savechanges:=False
End Sub

' テーブルスタイル設定
Private Sub ListSet()
  Dim Ret As Variant
  Worksheets(1).Select
  Range("A1").Select
  Range(Selection, Selection.End(xlToRight)).Select
  Range(Selection, Selection.End(xlDown)).Select
  Ret = ActiveSheet.ListObjects.Add(SourceType:=xlSrcRange, _
     Source:=Selection.Cells, xllistobjecthasheaders:=xlYes)
  With ActiveSheet.ListObjects(1)
   Select Case Int(Rnd * 3)
   Case 0
    .TableStyle = "TableStyleLight" & Int(Rnd * 20 + 1)
   Case 1
    .TableStyle = "TableStyleMedium" & Int(Rnd * 27 + 1)
   Case 2
    .TableStyle = "TableStyleDark" & Int(Rnd * 10 + 1)
   End Select
 End With
End Sub


最新の画像もっと見る

2 Comments

コメント日が  古い順  |   新しい順
説明 (ブログオーナー)
2016-01-31 10:35:28
①.strUID,strPWD,strDSN
 は、DBの接続形態に依存します。
 テストでは、ACCESSを使用したので、strUID,strPWDは使いませんでしたが
 職場では、ODBC-ORACLEで、DSNファイル名は、マクロ名の一部から編集して
 複数のSIDで切り替えて使ってました。
 strUID,strPWD,strDSNは、SQLシートのセルから、取得するようにするのも
 ありだと思います。

②.SQL読込み(SQLシート)
 Sheets("SQL").Visible = True
 Sheets("SQL").Visible = False
で、表示・非表示させて読み込んでます。
 ユーザーが自分でない場合
 SQLは見せたくない場合を想定して入れています。

③.DB接続 環境により設定
 複数の記述がありますが、
 ①と関連しますが、どういう環境で接続するのかで
 考えて選択します。
 DSNファイルは、移植が簡単かと・・・

④.見出しセット(未設定のとき)
 先頭のシートの1行目を見出し
 2行目以下をデータ展開エリアとしています。
 見出し行の書式をセットすると、行に設定するようにしています。
 都度しているのは、日付編集が
 CopyFromRecordset adoRsで、展開した後、消えてしまうということが
 あったのでしています。

⑤.書式設定(見出しセルに指定した書式を行に設定する)
 "yyyy/mm/dd;@"の場合だけ、特別に条件書式を設定しています。
 凝ったことを敢えてしている(趣味で)ので、
 不要ならば削除すれば、もっと簡略になります。

⑥.シート書出し
 出力ファイル名に日付(既にあれば時刻も)を付けています。
 いつも同じでいいなら、簡略化可能です。
 ボタンを削除、テーブルスタイル設定も冗長なので簡略化できます(削除可能です)。
 書き出したあと、マクロのブックは、閉じる設定にしています。
 マクロブックの変更があったら、書出し前に保存しておく設定です。

ご質問や、機能追加の要望とか、(あるいは不具合のご指摘は)コメントを頂けるとありがたいです。
返信する
最簡略化ソース (ブログオーナー)
2016-02-01 09:27:30
冗長な部分を削除した最小型を作成してみました。
DBは、ACCESSで固定、見出しは既に1行目に編集されている前提です。
SQLを一列のセルにせず、1セルにすれば更に簡潔化できますが、
それはまあ、いいでしょう。

******************************************************************
' SQL実行
Sub SQL_RUN()
 Dim adoCn As ADODB.Connection: Set adoCn = New ADODB.Connection
 Dim adoRs As ADODB.Recordset: Set adoRs = New ADODB.Recordset
 Dim i   As Integer: i = 1
 Dim strSQL As String: strSQL = ""

 Sheets("SQL").Select
 Do While Not (Cells(i, 1).Value = "")
  strSQL = strSQL + Cells(i, 1).Value
  i = i + 1
 Loop

 Sheets(1).Select
 If Not (Cells(1, 1).Value = "") And Not (Cells(2, 1).Value = "") Then
  Range(Cells(2, 1), Cells(Range("A2").End(xlDown).Cells.Row, _
               Range("A1").End(xlToRight).Cells.Column)).Select
  Selection.Borders.LineStyle = xlNone
  Selection.ClearContents
 End If

 adoCn.Open "FileDSN=" & ThisWorkbook.Path & "\TEST.dsn;"
 adoRs.Open strSQL, adoCn, adOpenStatic, adLockReadOnly ' SQL実行
 Range("A2").CopyFromRecordset adoRs
 adoRs.Close
 adoCn.Close
 Set adoRs = Nothing
 Set adoCn = Nothing

 Range("A2").Select
 If Selection.Value = "" Then Exit Sub
 Range(Cells(2, 1), Cells(Range("A2").End(xlDown).Cells.Row, _
              Range("A1").End(xlToRight).Cells.Column)). _
           Borders.LineStyle = xlContinuous
End Sub

' シート書出し
Sub SheetOut()
 Dim strFileName As String
 strFileName = ThisWorkbook.Path & "" & Replace(ThisWorkbook.Name, "xlsm", "")

 Sheets(1).Select
 Worksheets(1).Move
 ActiveWorkbook.SaveAs Filename:=strFileName & ".xlsx", FileFormat:=xlWorkbookDefault
 ThisWorkbook.Close savechanges:=False
End Sub
返信する

post a comment

ブログ作成者から承認されるまでコメントは反映されません。