本記事では、CSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートする方法についてご説明します。
【動画】ExcelのマクロからSQL ServerのテーブルデータだけをCSVファイルに出力する実際の動き
本題に入る前に、まずはCSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートする実際の動きについて、次のツイートをご覧ください。
ExcelのマクロからSQL ServerにCSVファイルのデータを条件を付けてインポートする処理を作ってみました😊
SQL ServerのBULK INSERTコマンドは条件を絞れず全件インポートなので
一時テーブルに全件インポート
一時テーブルから条件を絞り対象テーブルに挿入って感じにしました😃#VBA#SQLServer pic.twitter.com/RCOFQg6nbt
— まさ@Excel、VBA、マクロ(経験年数16年) (@masamasa9785) July 18, 2021
ツイート内の動画では、CSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートしています。
本記事ではCSVファイルのデータをインポートするのにBULK INSERTコマンドを利用します
本記事では、CSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートするのに、BULK INSERTコマンドを利用します。
BULK INSERTコマンドとは、SQL Serverのコマンドの一つで、データファイル(CSVファイルやテキストファイルなど)をSQL Serverのテーブルにインポートすることができるコマンドです。
今回はこのBULK INSERTコマンドを実行するストアドプロシージャを用意しておき、そのストアドプロシージャをExcelのマクロが呼び出すことで、CSVファイルのデータをSQL Serverのテーブルにインポートします。
【参考】
BULK INSERTコマンドに関するMicrosoftのリファレンスサイト
【課題と解決方法】BULK INSERTコマンドは条件に合致したデータだけをインポートすることはできない
BULK INSERTコマンドはCSVファイルのデータをSQL Serverのテーブルにインポートするのにとても便利ですが、BULK INSERTコマンドは条件に合致したデータだけをインポートすることはできません。
(CSVファイルの取り込み開始行、または最終行の位置を指定することはできますが)
例えば、文字列「〇〇」が含まれているデータだけインポートする、数値「〇〇」以上のデータだけインポートするなど、条件に合致したデータだけをインポートすることはできません。
そこで、次の方法で課題を解決します。
対象テーブルにはCSVファイルのデータはインポートはせず、一時テーブルにBULK INSERTでCSVファイルのデータをインポートさせ、その一時テーブルから条件に合致するデータだけを取り出して対象のテーブルに挿入させるというわけです。
以上の流れを踏まえたうえで、次項からはCSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートする方法について詳しくご説明していきます。
CSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートする方法
ExcelのマクロからSQL ServerのテーブルデータをCSVファイルに出力するには、次の流れの通りにコードを書いていきます。
Excelのマクロ側
ストアドプロシージャを実行するにはまずはDBに接続しなければなりませんが、接続する情報(ユーザ名やパスワードといった接続情報)がなければDBに接続できません。
SQL Serverに接続に接続するには、ConnectionオブジェクトのOpenメソッドを使います。
設定する情報は、次の通りです。
・SQL Serverのデータソースに対してストアドプロシージャを実行する場合に定数「adCmdStoredProc」を指定
・(BULK INSERTコマンドを実行する)ストアド名
設定するものは、次の通りです。
・パラメタ名
・パラメタの型
・パラメタの値
なお本記事では、ストアドプロシージャに次の4つのパラメタを渡しています。
①CSVファイル名
②挿入する条件(SQL)
⇒条件に合致するデータを、この「挿入する条件(SQL)」で指定します。
③データを挿入する対象のテーブル名
⇒条件に合致するデータだけをインポートするテーブルです。
④一時テーブル名
⇒BULK INSERTコマンドでCSVファイルのデータをインポートする一時テーブルです。
処理の最後にDROPコマンドで削除します。(ストアドプロシージャ内で削除)
ストアドプロシージャ側
本記事では、受け取る値は次の通りです。
①CSVファイル名
②挿入する条件(SQL)
③データを挿入する対象のテーブル名
④一時テーブル名
挿入する際は、条件に合致するデータを条件に指定して挿入します。
ソースコード
Excelのマクロのコード(例)
Excelのマクロのコード(例)は次の通りです。
'変数定義 Dim DBName As String, connDB As String, CSVFile As String, prmNameValAry() As Variant, cnt As Integer Dim objConnection As ADODB.Connection Dim objCommand As ADODB.Command Dim objParameter As ADODB.Parameter 'データベース接続情報を取得 DBName = "testDataDB" connDB = "Provider=SQLNCLI11.1;" connDB = connDB & "Data Source=(LocalDB)\MSSQLLocalDB;" connDB = connDB & "Initial Catalog=" & DBName & ";" connDB = connDB & "Trusted_Connection=yes;" 'パラメタ名とパラメタ値を配列に格納 '①CSVファイル名 '②挿入する条件(SQL) '③データを挿入する対象のテーブル '④一時テーブル名 prmNameValAry = Array( _ Array("insertDataFilePath", _ "conditionsStr", _ "insToTbl", _ "tmpTbl" _ ), _ Array(ThisWorkbook.Path & "\" & Range("D2").Value, _ Range("D3").Value, _ Range("D4").Value, _ Range("D5").Value _ ) _ ) 'DBへの接続 Set objConnection = New ADODB.Connection objConnection.CursorLocation = adUseClient objConnection.Open connDB '実行するストアドプロシージャを設定 Set objCommand = New ADODB.Command Set objCommand.ActiveConnection = objConnection objCommand.CommandType = adCmdStoredProc objCommand.CommandText = "dbo.sp_std_info" 'ストアドプロシージャ名 'ストアドプロシージャのパラメタに渡す値の設定(渡したいパラメタの数だけ繰り返す) For cnt = 0 To UBound(prmNameValAry(0), 1) 'パラメタオブジェクトの作成 Set objParameter = objCommand.CreateParameter() 'パラメタ名(ストアド側の変数名と合わせること) objParameter.Name = prmNameValAry(0)(cnt) 'データ型の指定(ここでは文字列を指定) objParameter.Type = adWChar 'CSVファイル名(の文字列)のサイズ指定 objParameter.Size = Len(prmNameValAry(1)(cnt)) 'ストアドプロシージャの引数に渡す値 objParameter.Value = prmNameValAry(1)(cnt) '入力パラメータ objParameter.Direction = adParamInput 'ストアドプロシージャの引数に渡す値を設定する objCommand.Parameters.Append objParameter Next 'ストアドプロシージャの呼び出し objCommand.Execute '後処理 Set objParameter = Nothing Set objCommand = Nothing Set objConnection = Nothing
コードの解説
注目すべきコード①
最初に見て頂きたいのは70行目です。
この70行目でストアドプロシージャを呼び出しています。
注目すべきコード②
次に見て頂きたいのは19行目から30行目です。
ストアドプロシージャに渡したいパラメタ4つをここで用意しています。
- ①CSVファイル名
- ②挿入する条件(SQL)
- ③データを挿入する対象のテーブル名
- ④一時テーブル名
※このコードの記述はあくまで一例です。ストアドプロシージャに渡したいパラメタ4つが用意出来ればどんな書き方でも構いません。
注目すべきコード③
呼び出すストアドプロシージャ名は41行目で指定し、47行目から65行目でストアドプロシージャに渡すパラメタの設定を行います。
設定するものは、次の通りです。
・パラメタ名
・パラメタの型
・パラメタの値
以上のストアドプロシージャに渡すパラメタの設定を、ストアドプロシージャに渡すパラメタの数だけ繰り返し行っています。(パラメタが4つあるので4回繰り返しています)
ストアドプロシージャのコード(例)
ストアドプロシージャのコード(例)は次の通りです。
USE [testDataDB] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[sp_std_info] --Excel側から渡された引数 @insertDataFilePath NVARCHAR(100) --CSVファイル名(フルパス) ,@conditionsStr NVARCHAR(100) --(テーブル挿入の)条件 ,@insToTbl NVARCHAR(100) --データを挿入する対象のテーブル ,@tmpTbl NVARCHAR(100) --一時テーブル AS BEGIN SET NOCOUNT ON; --変数定義 DECLARE @SQL NVARCHAR(1000); --SQL文 DECLARE @RtnCd INT; --エラーコード DECLARE @RtnMsg VARCHAR(2000); --エラーメッセージ --変数の初期化 SET @SQL = ''; BEGIN TRY BEGIN TRANSACTION; --CSVファイルのデータをインポートする前に、データを挿入する対象のテーブルデータを削除する SET @SQL = N' delete from ' + @insToTbl; EXEC sp_executesql @SQL; --(データを挿入する対象のテーブルを元に)一時テーブルを作成 SET @SQL = N' SELECT * INTO ##' + @tmpTbl + ' FROM ' + @insToTbl; EXEC sp_executesql @SQL; --CSVファイルを一時テーブルにインポートする SET @SQL = N' BULK INSERT ##' + @tmpTbl + N' FROM ''' + @insertDataFilePath + '''' + --Excel側から渡されたCSVファイル N' WITH' + N' (' + N' FIELDTERMINATOR = '',''' + --データがカンマ区切り N' ,ROWTERMINATOR = ''\n''' + --終端が改行コード(\n) N' ,FIRSTROW = 2 ' + --インポートするデータの開始行 N' );' EXEC sp_executesql @SQL; --一時テーブルのデータを、データを挿入する対象のテーブルに条件に合致するデータだけを挿入する SET @SQL = N' insert into ' + @insToTbl + ' ' + @conditionsStr; EXEC sp_executesql @SQL; --一時テーブルを削除する SET @SQL = N' drop table ##' + @tmpTbl; EXEC sp_executesql @SQL; COMMIT TRANSACTION; SET @RtnCd = 0; END TRY BEGIN CATCH IF @@TRANCOUNT <> 0 BEGIN ROLLBACK TRANSACTION; END; SET @RtnCd = ERROR_NUMBER(); SET @RtnMsg = ERROR_MESSAGE(); END CATCH; END GO
コードの解説
注目すべきコード①
最初に見て頂きたいのは56行目です。
一時テーブルのデータを、データを挿入する対象のテーブルに条件に合致するデータだけを挿入しています。
一時テーブルのデータから、条件に合致するデータだけを抽出し、そのデータを挿入する対象のテーブルに挿入しています。
合致する条件(文)はExcelのマクロから渡されて、変数「@conditionsStr」に格納されています。
注目すべきコード②
次に見て頂きたいのは40行目です。
ここで一時テーブルを作成しています。
一時テーブルを作成するのにCreate文は使わず、「SELECT * INTO」を使ってデータを挿入する対象のテーブルを元に一時テーブルを作成しています。
つまり、データを挿入する対象のテーブルをコピーして一時テーブルを作成しているというわけです。
テーブルの構造は全く同じで一時テーブルを用意したかったので、「SELECT * INTO」を使った方が楽ですし、コード数も少なく済むため「SELECT * INTO」を使って一時テーブルを作成しています。
注目すべきコード③
最初に見て頂きたいのは44行目から51行目です。
このコードがBULK INSERTコマンドを実行するためのコードです。
変数「SQL」にBULK INSERTコマンドを実行するためのコードを格納し、53行目で実行します。
【注意】参照設定が必要です
一つ注意点があるのですが、先ほどのExcelのマクロのコードを動かすには参照設定が必要です。
参照設定の一覧(下の画像を参考)から次の項目(ライブラリ)にチェックを付けて「OK」ボタンをクリックします。
- Microsoft ActiveX Data Objects 2.8 Library(msado28.tlb)
なぜ必要かというと、先ほどのコードの3行目の「ADODB.Connection」と4行目の「ADODB.Command」、5行目の「ADODB.Parameter」というオブジェクトが、「msado28.tlb」というファイルを参照するからです。
Dim objConnection As ADODB.Connection Dim objCommand As ADODB.Command Dim objParameter As ADODB.Parameter
この参照設定をしないと下の画像のエラーが出ますので必ず行う必要があります。
ここでは「msado28.tlb」とは何者かについては記事の本題から逸れてしまうので詳細は割愛しますが、マクロで「ADODB.Connection」というオブジェクトを使う場合は参照設定しないと動かない、程度に思って頂ければと思います。
最後に
本記事では、CSVファイルのデータの中から条件に合致するデータだけをSQL Serverのテーブルにインポートする方法についてご説明しました。
CSVファイルのデータをSQL Serverのテーブルにインポートするのに、BULK INSERTコマンドを利用するのは便利ではあるものの、条件に合致するデータだけをインポートすることはできないため処理を工夫しなければなりません。
どのように工夫するのかというと、ザックリとした処理の流れとしては、
- ①一時テーブルの生成
- ②BULK INSERTコマンドを使って、①の一時テーブルにCSVファイルのデータをインポート
- ③条件に合致するインポートデータを抽出するSelect文を用意
- ④ ③のselect文で一時テーブルから抽出したデータを、対象のテーブルに挿入
以上になります。
あくまで今回紹介した方法は一つの例ですが、こんなやり方があるのかと参考にしていただけたら幸いです。
プログラミングのスキルを習得するなら
プログラミングのスキルを習得したい、今のスキルをもっと高めたい、そう考えているなら「プログラミングスクール」がおすすめです。
プログラミングのスキルの基礎を身につけるなら「TechAcademy」で1週間の無料体験があるので、これで「プログラミングの基礎」を学ぶのにおすすめですよ。