良い一日、
私は少し単純なVBAで問題を抱えています。テキストクエリ(入力パラメータがないため、実際のユーザー操作やSQLインジェクションなどがない)を取得し、データベースに対して実行して、新しいワークシートにダンプするスクリプトを作成しました。これは、一部の開発者分析では1回限りの単純なものであるため、機能は非常に単純です。
クエリがすべての列の値を返す場合、問題はありません。ただし、クエリにnull値が含まれている場合(私の場合はROLLUP()の結果として)、サブルーチン全体がMoveNextで失敗します(注:セルへのnull値の割り当てではありません)。元々、null行にアクセスする前に、スクリプトは失敗していました。
Range(Cells(2, 1), Cells(rsData.RecordCount + 1, rsData.Fields.Count)).NumberFormat = "@"
これはコメント化され、現在のセルがnullであるかどうかのチェックを追加する目的でセルごとに移動されました(インターネット上で最も一般的な提案)。
クエリはバックエンドSQLエディタを使用して検証されており、正しいです。私が読んだ他のすべての記事は、製品に固有のものであるか、該当しないものです。したがって、問題は単純です。レコードセットでnull値をどのように処理するのでしょうか。このサブは多くの異なるクエリに使用され、クエリに一連のNVL()ステートメントを追加する必要があるという考えは非常に不快であるため、データベース側でnullを削除することは避けたいと思います。
よろしくお願いします。完全なコードは次のとおりです。
Sub runReport(query As String, sheetName As String)
    Dim cnDatabase As ADODB.Connection
    Dim rsData As ADODB.Recordset
    Dim row As Integer
    Dim column As Integer
    'Create new worksheet
    Sheets.Add.Name = sheetName
    Excel.Application.Worksheets(sheetName).Select
    'Connect to database
    Set cnDatabase = New Connection
    cnDatabase.ConnectionString = "Provider=OraOLEDB.Oracle;Data Source=DB.EXAMPLE.COM;User ID=FOO;Password=BAR;ChunkSize=1000;FetchSize=100;"
    cnDatabase.Open
    'Retrieve dataset
    Set rsData = New Recordset
    Set rsData.ActiveConnection = cnDatabase
    rsData.Source = query
    rsData.CursorLocation = adUseClient
    rsData.CursorType = adOpenStatic
    rsData.Open
    'Output header row
    For column = 1 To rsData.Fields.Count
        Cells(1, column).Value = rsData.Fields(column - 1).Name
        Rows(1).Font.Bold = True
    Next
    'Set all fields as text
    'Range(Cells(2, 1), Cells(rsData.RecordCount + 1, rsData.Fields.Count)).NumberFormat = "@"
    'Output retrieved data from database
    row = 2
    While Not rsData.EOF
      For column = 1 To rsData.Fields.Count
         Cells(row, column).NumberFormat = "@"
         Cells(row, column).Value = rsData.Fields(column - 1).Value
      Next
      rsData.MoveNext
      row = row + 1
   Wend
   cnDatabase.Close
End Sub