| ■決まりごと | ||||||
| SPの頭に必ずつける決まり文句 | ||||||
|
| ■ファイル |
| ログを書く |
| xp_cmdshell と dosコマンド[echo]を使う。 例) |
| ■メール |
| メール設定 |
|
コマンドからメールを送るプログラムを xp_cmdshellで実行する方法と、 --メールの設定 |
| メールの送信 |
| 以下のクエリでメールの送信が出来ます。 EXEC master.dbo.xp_startmaill --メールセッションスタート --メール送信 EXEC master.dbo.xp_sENDmail @recipients='************' ,@subject='test2' ,@message='test2' EXEC master.dbo.xp_stopmail --メールセッションストップ ※ ********* にはメールアドレスを入力。 指定したアドレスにメールが送信されればOK メール受信時にメッセージの最後に変な文字が入ってしまう場合は、スペースを入れたりして回避してください。 |
| 複数送信のメールセッション複数開始の回避 |
|
メールセッションがスタートしているときに、xp_startmailでメールセッションをスタートさせようとすると、エラーが生じます。それを回避する方法を示します。 方法1:SQLサーバ起動時に自動実行されるSPを作り、そのなかで「EXEC master.dbo.xp_startmail」を実行しておく方法。SQLServerが動いているときは、 |
| ■バルクコピー |
| その1.テーブルの内容をファイルに書き出す |
| DECLARE @BCPSTR varchar(4000) -- FactDB.dbo.ContentsFactTABLEを丸々ファイルに落とす場合 SET @BCPSTR = 'bcp FactDB.dbo.ContentsFactTABLE out C:\FactDB_ContentsFactTABLE.txt -e C:\SQLWORK\FactDB_ContentsFactTABLEerror.txt -c -t, -U sa -P -o C:\SQLWORK\FactDB_ContentsFactTABLE.out' EXECUTE master.dbo.xp_cmdshell @BCPSTR |
| その2.テーブルの内容をファイルに書き出す |
| DECLARE @BCPSTR varchar(4000) SET @BCPSTR = 'bcp "SELECT A.ContentsFactID, A.AccessTime, A.RefSec, A.DayOfWeekID, A.HourID, A.StoredTime, A.TermID, A.UserID, A.ExeNameID, A.FileVersionID, ' +' A.ProtocolID, A.ClickedDomainID, A.ClickedSubDomainID, A.ClickedURLID, A.MetaFileDomainID, A.MetaFileSubDomainID, A.MetaFileURLID, ' +' A.MetaFileExtensionID, A.ContentsDomainID, A.ContentsSubDomainID, A.ContentsURLID, A.ContentsExtensionID, A.MetaTitleID, A.MetaAuthorID, ' +' A.MetaCopyrightID, A.AreaCode1ID, A.PrefectureCodeID, A.SexAgeCode1ID, A.SexAgeCode2ID, A.SexAgeCode3ID, A.Age, A.Sex, A.BusinessCode1ID, ' +' A.BusinessCode ' +' FROM '+@ChvPreServerName+'.FactDB.dbo.ContentsFactTABLE AS A, '+@ChvPreServerName+'.WebReportDB.dbo.WebPanelInUserInfoTABLE AS B ' +' WHERE B.UserID = A.UserID and '+CAST(@IntMaxSELECTedContentsFactID AS CHAR)+' < A.ContentsFactID " queryout C:\FactDB_ContentsFactTABLE.txt -e C:\FactDB_ContentsFactTABLEerror.txt -c -t , -S '+@ChvOrigenalPreServerName+' -U '+@ChvPreID+' -P '+@ChvPrePass+' -o C:\FactDB_ContentsFactTABLE.out' EXECUTE master.dbo.xp_cmdshell @BCPSTR |
| その3.ファイルからテーブルに読み込み |
| DECLARE @BCPSTR varchar(4000) SET @BCPSTR = 'bcp FactDB.dbo.SELECTedContentsFactTABLE in C:\FactDB_ContentsFactTABLE.txt -c -t, -S '+@ChvOrigenalPreServerName+' -U '+@ChvPreID+' -P '+@ChvPrePass+' -o C:\FactDB_ContentsFactTABLE.out' EXECUTE master.dbo.xp_cmdshell @BCPSTR |
| その4."文字のある文字列をバルクインサートする |
| 出来ません。 と、言うのも冷たいので以下を参照して下さい。 頑張りまくれば可能です。 →拡張SP(ストアドプロシージャ):"文字のある文字列をバルクインサートする |
| ■カーソル |
| 使い方 |
| カーソルはSELECT分を1レコードずつ回したいときに使います。(レコードセットで一気にとらずに、レコード一つずつとりたいとき) 例)#tmpSamplesという一時テーブルに日付が入っているとします。 DECLARE @CrsrTmpSample cursor --サンプル数計算時に使用するカーソル DECLARE @DtmTmpDateID --カーソルでとった値を入れる --カーソルをセットします。 SET @CrsrTmpSamples = cursor for SELECT DateID FROM #tmpSamples --カーソルを開きます。 open @CrsrTmpSamples --レコードセットから1レコード取得します。 fetch next FROM @CrsrTmpSamples INTO @DtmTmpDateID WHILE( @@FETCH_STATUS = 0 ) --レコードセットの最後までループ BEGIN --ここで加工などを行う。 print @DtmTmpDateID --次のレコードを取得します。 fetch next FROM @CrsrTmpSamples INTO @DtmTmpDateID END --END WHILE -- カーソルを閉じる close @CrsrTmpSamples deallocate @CrsrTmpSamples |
| ■テーブル |
| テーブルロック |
| [WITH]オプションを使うことによってテーブルのロックができます。 例1) 以下の例では、このSELECT文が終了するまで、他の人はTestTABLEの参照、更新が出来なくなります。 SELECT * FROM TestTABLE WITH (TABLOCKX) 例2) トランザクションをはってその中でロックを行った場合は、TestTABLEはトランザクションが終了するまで、分離レベルを無視してロックされたままになります。 (トランザクション、分離レベルについては、SQLServerのBooksOnlineを参照。) start tran SELECT * FROM TestTABLE WITH (TABLOCKX) commit tran --コミットする。 |
| レコードセットを返す際の一時テーブル |
|
ASPからストアドを実行し、レコードセットを取得する際などにおいて。 |
| 一時テーブルに中身があるときだけ検索条件に加えるSELECT文 |
| 曜日番号の入った一時テーブル #tmpWeekID があります。 このテーブルで指定した曜日のデータを取りたい場合、以下のようなクエリを書きます。 SELECT * FROM MainTABLE M WHERE M.WeekID IN (SELECT WeekID FROM #tmpWeekID)) しかし、この場合 #tmpWeekID の中身が空の場合は、レコードが1件も取れません。中身が空の場合は全曜日を対象としたい場合は、以下のようなクエリを書きます。 SELECT * FROM MainTABLE M WHERE ( not exISts(SELECT * FROM #tmpWeekID ) or (M.WeekID IN (SELECT WeekID FROM #tmpWeekID)) ) これで、#tmpWeekIDの中身が空のときは全曜日が対象になり、中身がある場合はその曜日が対象になります。 |
| テーブルを縦に繋ぐ(UNION) |
| UNION を使ってください。 例) SELECT A,B FROM TestATABLE union SELECT A,B FROM TestBTABLE ORDER BY A ※ただし ORDER BYは最後にしか付けられないので注意!! |
| ■動的クエリ |
| 動的クエリの実行(変数に文字列を入れてそれをクエリとして実行) |
|
sp_EXECutesql を使います。これによって通常のクエリでは動的に指定できないDB名,テーブル名,列名なども可変にできます。 |
| ■存在確認 |
| DBの存在確認法 |
|
--master..sysdatabasesテーブルを見ることで確認できます。 IF exISts( SELECT * FROM master.dbo.sysdatabases WHERE name = 'TESTDB' ) BEGIN print 'DBあり' END |
| テーブルの存在確認法 |
|
--調べたいDBのsysobjectsテーブルを見ることで確認できます。 IF exISts(SELECT * FROM TESTDB.dbo.sysobjects WHERE id = object_id ( N'[TESTDB].[dbo].[TESTTABLE]') and xtype ='U') BEGIN print 'テーブルあり' END |
| 一時テーブルの存在確認法 |
|
-- tmpdb..sysobjects を見ることで確認できます。 -- その際に OBJECT_IDを使ってIDを取得する必要があります。 IF exISts(SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID('tempdb.dbo.#tmpTESTTABLE') and xtype = 'U') BEGIN print '一時テーブルあり' END |
| プロセスの存在確認 |
|
自分のプロセスID(spid)は @@SPID で取得できます。 |
| フォルダの存在確認 |
| xp_cmdshell と DOSコマンド "dir"
を使います。 例) DECLARE @ChvCmd varchar(8000) -- DOSコマンド文字列 DECLARE @IntRet int -- DOSコマンドの戻り値 SET @ChvCmd = 'dir ' + @ChvLogFilePath + ' /b' EXEC @IntRet = master.dbo.xp_cmdshell @ChvCmd, no_OUTPUT IF @@ERROR <> 0 BEGIN print '指定したフォルダを見つけられません。' END |
| ■ヌル(NULL) |
| SET @ChvTmp = 'abc' + NULL はNULL |
| NULL を足すと NULL になります。数値も同じです。 |
| ■日時 |
| datetime型から年月日を取得 |
| DECLARE @DtmTmp datetime SET @DtmTmp = GETDATE() SELECT CONVERT(char(10),@DtmTmp,111) |
| 今週の月曜日の取得 |
| 指定年月日の週の月曜日の日付を取得するサンプルです。 指定年月日が日曜の時は、前の週の月曜日を取得します。 DECLARE @DtmTargetDate datetime -- 指定年月日 DECLARE @DtmMonday datetime --指定年月日の週の月曜日の日付 DECLARE @INTOffSET int --指定年月日の週の月曜日を求める為に使用 ------------------------------------------------------- -- 指定年月日の週の月曜日を取得 ------------------------------------------------------- -- DATEPARTの戻り値(日曜日:1,土曜日:7) SET @INTOffSET = DATEPART(weekday, @DtmTargetDate) -- 日曜日だけ特別に[6]に、他の日は[曜日-2]にすることで、前週の月曜日を求める。 IF @INTOffSET = 1 BEGIN SET @INTOffSET = 6 END ELSE BEGIN SET @INTOffSET = @INTOffSET - 2 END SET @DtmMonday = DATEADD(DAY, -1 * @INTOffSET, @DtmTargetDate) SELECT @DtmMonday |
| 秒を何時間:何分:何秒の形式にする |
| 50000秒 → 13:53:20(13時間53分20秒) に変換したいとき。 下記のようなクエリを使います。(ユーザ定義関数にしてもいい。) DECLARE @IntMinute -- 秒 SET @IntMinute = 5000 DECLARE @IntTmp SET @IntTmp = DATEADD(second,@IntMinute,0) --1900/1/1 **:**:**の形にする。 SELECT CONVERT(varchar,DATEDIFF( hour,0,@IntTmp)) --[時] 1900/1/1 00:00:00 との差 + ':' + RIGHT('00' + CONVERT(varchar,DATEPART( minute,@IntTmp)),2) --[分] + ':' + RIGHT('00' +CONVERT(varchar,DATEPART( second,@IntTmp)),2) --[秒] |
| 今週の月曜日の日付を求める |
| DECLARE @DtmToday DATETIME SET @DtmToday = GETDATE() -- DATEPART:1日 2月 3火 4水 5木 6金 7土 IF DATEPART( WEEKDAY, @DtmToday ) = 1 SET @DtmToday = DATEADD( DD, 1, @DtmToday ) ELSE IF DATEPART( WEEKDAY, @DtmToday ) = 3 SET @DtmToday = DATEADD( DD, -1, @DtmToday ) ELSE IF DATEPART( WEEKDAY, @DtmToday ) = 4 SET @DtmToday = DATEADD( DD, -2, @DtmToday ) ELSE IF DATEPART( WEEKDAY, @DtmToday ) = 5 SET @DtmToday = DATEADD( DD, -3, @DtmToday ) ELSE IF DATEPART( WEEKDAY, @DtmToday ) = 6 SET @DtmToday = DATEADD( DD, -4, @DtmToday ) ELSE IF DATEPART( WEEKDAY, @DtmToday ) = 7 SET @DtmToday = DATEADD( DD, -5, @DtmToday ) PRINT @DtmToday |
| 月曜日かどうか調べる |
| DECLARE @DtmToday DATETIME SET @DtmToday = GETDATE() IF DATEPART( WEEKDAY, @DtmToday ) = 2 BEGIN PRINT '月曜日です。' END ELSE BEGIN PRINT '月曜日ではありません。' END |
| 1週間前の月曜日を求める |
| DECLARE @DtmDate DATETIME SET @DtmDate = GETDATE() IF DATEPART( WEEKDAY, @DtmDate ) != 1 -- 日曜以外 BEGIN SET @DtmDate = ( DATEADD( DD, -( 5 + DATEPART( WEEKDAY,@DtmDate ) ), @DtmDate ) ) END ELSE IF DATEPART( WEEKDAY, @DtmDate ) = 1 -- 日曜 BEGIN SET @DtmDate = DATEADD( dd, -13, @DtmDate ) END |
| 2つの日付の差が1週間か調べる |
| DECLARE @DtmFIStDate DATETIME DECLARE @DtmSecondDate DATETIME IF DATEDIFF( DAY, @DtmFIStDate, @DtmSecondDate ) = 6 BEGIN PRINT '差は1週間です。' END ELSE BEGIN PRINT '差は1週間ではありません。' END |
| 日時が23時59分59秒か調べる |
| DECLARE @DtmDate DATETIME SET @DtmDate = GETDATE() IF DATEPART( HOUR, @DtmDate ) <> 23 or DATEPART( MINUTE, @DtmDate ) <> 59 or DATEPART( SECOND, @DtmDate ) < 59 BEGIN PRINT '23時59分59秒ではありません。' END ELSE BEGIN PRINT '23時59分59秒です。' END |
| 前の週か調べる |
| SET @DtmDate = DATEADD( DAY, -1, @DtmDate ) DECLARE @DtmTmpToday DATETIME SET @DtmTmpToday = DATEADD( DAY, -1, GETDATE() ) IF DATEDIFF( WEEK, @DtmDate, @DtmTmpToday ) <> 1 BEGIN PRINT '先週の日付ではありません。' END ELSE BEGIN PRINT '先週の日付です。' END |
| 13ヶ月前を求める |
| DECLARE @DtmDate DATETIME SET @DtmDate = GETDATE() SET @DtmDate = ( DATEADD( MM ,-13, @DtmDate ) ) |
| 時分秒をカットする |
| DECLARE @DtmDate DATETIME SET @DtmDate = CONVERT( CHAR(10), @DtmDate, 111 ) |
| 日付がたくさんあるテーブルから最大の日付を取得する |
| DECLARE @DtmUsableDate DATETIME DECLARE @ChvUsableDBName VARCHAR (255) SELECT UsableDate, UsableDBName FROM ASPDB.dbo.CategoryChangeTABLE WHERE ( UsableDate = ( SELECT MAX( UsableDate ) FROM ASPDB.dbo.CategoryChangeTABLE ) ) 例:テーブルレイアウト ASPDB.dbo.CategoryChangeTABLE UsableDate:Datetime UsableCategoryName:VARCHAR |
| ■Excel(エクセル) |
| SP(ストアドプロシージャ)でExcel(エクセル)ファイルを扱うには |
| SP(ストアドプロシージャ)内でExcel(エクセル)ファイルを扱うには、COMを使用します。 COMといってもC++、VC++などのCOMと違い、予め用意されたExcelのCOMを操作するSPを使用します。 これはExcel(エクセル)だけに特化したことではなく、COMで作成されたアプリケーションはこのようなCOMを扱うSPをコールして操作します。 COMを扱うSP(ストアドプロシージャ)には以下のものが存在します。 ・sp_OACreate ・sp_OADestroy ・sp_OAGetErrorInfo ・sp_OAGetProperty ・sp_OAMethod ・sp_OAStop ・sp_OASetChvProperty |
| sp_OACreate |
| OLE オブジェクトのインスタンスを作成します。 ■構文 sp_OACreate { progid | clsid } , objecttoken OUTPUT [ , context ] ■引数 progid 作成する OLE オブジェクトのプログラム ID (ProgID) を指定します。これは OLE オブジェクトのクラスを説明する文字列で、'OLEComponent.Object' の形式で指定します。 OLEComponent は OLE オートメーション サーバーのコンポーネント名で、Object は OLE オブジェクト名です。指定した OLE オブジェクトは有効かつ IDispatch インターフェイスをサポートする必要があります。 たとえば、SQLDMO.SQLServer は SQL-DMO SQLServer オブジェクトの ProgID です。SQL-DMO は SQLDMO のコンポーネント名であり、SQLServer オブジェクトは有効かつすべての SQL-DMO オブジェクトと同様に IDispatch インターフェイスをサポートしています。 clsid 作成する OLE オブジェクトのクラス ID (CLSID) を指定します。これは OLE オブジェクトのクラスを説明する文字列で、 '{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}' の形式で指定します。 指定した OLE オブジェクトは有効かつ IDispatch インターフェイスをサポートする必要があります。 objecttoken 返されるオブジェクト トークンです。int 型 (整数型) のローカル変数になります。このオブジェクト トークンは、作成する OLE オブジェクトを識別するもので、その他の OLE オートメーション ストアド プロシージャの呼び出しに使用されます。 context 新しく作成した OLE オブジェクトを実行するときの実行条件を指定します。指定する場合は、次のいずれかの値を指定する必要があります。 1 = 組み込み (.dll) OLE サーバーのみ。 4 = ローカル (.exe) OLE サーバーのみ。 5 = 組み込みおよびローカル OLE サーバーの両方が有効。 値を指定しない場合は、既定値 5 が使用されます。この値は、CoCreateInstance への呼び出しの dwClsContext パラメータとして渡されます。 context 値に 1 または 5 を使用するか、context 値を指定しないで、組み込み OLE サーバーを有効にした場合は、SQL Server が所有するメモリおよびその他のリソースにアクセスできます。組み込み OLE サーバーは、SQL Server のメモリやリソースに損傷を与え、SQL Server のアクセス違反など予期しない結果を招く場合があります。 context 値に 4 を指定した場合、ローカル OLE サーバーは SQL Server のどのリソースにもアクセスすることなく、SQL Server のメモリやリソースに損傷を与えることはありません。 ■戻り値 成功した場合は 0、失敗した場合は OLE オートメーション オブジェクトによって返される HRESULT の 0 以外の整数値を返します。 |
| sp_OADestroy |
| 作成した OLE オブジェクトを破棄します。 ■構文 sp_OADestroy objecttoken ■引数 objecttoken 以前に sp_OACreate で作成した OLE オブジェクトのオブジェクト トークンを指定します ■戻り値 成功した場合は 0 を、失敗した場合は OLE オートメーションが返す HRESULT の 0 以外の整数値をそれぞれ返します。 |
| sp_OAGetErrorInfo |
| OLE オートメーションのエラー情報を取得します。 ■構文 sp_OAGetErrorInfo [ objecttoken ] [ ,source OUTPUT ] [ ,description OUTPUT ] [ ,helpfile OUTPUT ] [ ,helpid OUTPUT ] ■引数 objecttoken 以前に sp_OACreate で作成した OLE オブジェクトのオブジェクト トークン、または NULL を指定します。 objecttoken を指定した場合、そのオブジェクトのエラー情報が返されます。 NULL を指定した場合は、そのバッチ全体のエラー情報が返されます。 source エラー情報のソースです。指定する場合、値はローカルの char、nchar、varchar、または nvarchar 型の変数にする必要があります。 戻り値は必要に応じてローカル変数のサイズに切り捨てられます。 description エラーの説明です。指定する場合、値はローカルの char、nchar、varchar、または nvarchar 型の変数にする必要があります。 戻り値は必要に応じてローカル変数のサイズに切り捨てられます。 helpfile OLE オブジェクトのヘルプ ファイルです。指定する場合、値はローカルの char、nchar、varchar、または nvarchar 型の変数にする必要があります。 戻り値は必要に応じてローカル変数のサイズに切り捨てられます。 helpid ヘルプ ファイルのコンテキスト ID です。指定する場合、値はローカルの int 型の変数にする必要があります。 ■戻り値 成功した場合は 0、失敗した場合は OLE オートメーション オブジェクトによって返される HRESULT の 0 以外の整数値を返します。 |
| sp_OAGetProperty |
| OLE オブジェクトのプロパティ値を取得します。 ■構文 sp_OAGetProperty objecttoken , propertyname [ ,propertyvalue OUTPUT ] [ , index...] ■引数 objecttoken 以前に sp_OACreate で作成した OLE オブジェクトのオブジェクト トークンです propertyname 返される OLE オブジェクトのプロパティ名です。 propertyvalue 返されるプロパティ値です。指定する場合は、適切なデータ型のローカル変数でなければなりません。 プロパティが OLE オブジェクトを返す場合は、propertyvalue は int 型のローカル変数であることが必要です。 オブジェクト トークンがローカル変数に格納され、このオブジェクト トークンを他の OLE オートメーション ストアド プロシージャで使用できます。 プロパティが単一の値を返す場合、propertyvalue にローカル変数を指定すると、プロパティ値がローカル変数で返されます。 propertyvalue を指定しないと、プロパティ値が、単一列、単一行の結果セットとしてクライアントに返されます。 プロパティが配列を返すときに、propertyvalue を指定する場合は、NULL を設定します。 propertyvalue が指定され、プロパティが値を返さない場合は、エラーが発生します。 プロパティが 3 次元以上の配列を返す場合は、エラーが発生します。 index インデックス パラメータです。指定する場合、index は適切なデータ型の値にする必要があります。 プロパティの一部はパラメータを持っています。 このようなプロパティをインデックス付きプロパティ、パラメータをインデックス パラメータと呼びます。 1 つのプロパティが複数のインデックス パラメータを持つことができます。 ■戻り値 成功した場合は 0 を、失敗した場合は OLE オートメーションが返す HRESULT の 0 以外の整数値をそれぞれ返します。 |
| sp_OAMethod |
| OLE オブジェクトのメソッドを呼び出します。 ■構文 sp_OAMethod objecttoken , methodname [ , returnvalue OUTPUT ] [ , [ @parametername = ] parameter [ OUTPUT ] [ ...n ] ] ■引数 objecttoken 以前に sp_OACreate で作成した OLE オブジェクトのオブジェクト トークンです。 methodname 呼び出す OLE オブジェクトのメソッド名です。 returnvalue OLE オブジェクトのメソッドの戻り値です。指定する場合は、適切なデータ型のローカル変数でなければなりません。 メソッドが単一の値を返す場合は、returnvalue にローカル変数を指定すると、メソッドの戻り値をローカル変数に返します。 returnvalue を指定しない場合は、メソッドの戻り値を単一列、単一行の結果セットとしてクライアントに返します。 メソッドの戻り値が OLE オブジェクトである場合、returnvalue のローカル変数は int 型 (整数型) であることが必要です。 オブジェクト トークンがローカル変数に格納され、このオブジェクト トークンを他の OLE オートメーション ストアド プロシージャで使用できます。 メソッドの戻り値が配列の場合に returnvalue を指定すると、NULL に設定されます。 次のいずれかの状況になると、エラーが発生します。 ・returnvalue が指定され、メソッドが値を返さない場合 ・メソッドが 3 次元以上の配列を返す場合 ・メソッドが出力パラメータとして配列を返す場合 [ @parametername = ] parameter メソッド パラメータです。指定する場合、parameter は適切なデータ型の値にする必要があります。 出力パラメータの戻り値を取得するには、parameter は適切なデータ型のローカル変数で、OUTPUT を指定する必要があります。 定数 parameter を指定する場合、または OUTPUT を指定しない場合は、出力パラメータからの戻り値は無視されます。 指定した場合、parametername は、Microsoft Visual Basic の名前付きパラメータの名前にする必要があります。 @parametername は、Transact-SQL のローカル変数ではありません。 アット マーク (@) は削除され、parametername はパラメータ名として OLE オブジェクトに渡されます。 すべての名前付きのパラメータは、位置で決まるパラメータをすべて指定した後で指定する必要があります。 n 複数のパラメータを指定できることを示すプレースホルダです。 ■戻り値 成功した場合は 0 を、失敗した場合は OLE オートメーションが返す HRESULT の 0 以外の整数値をそれぞれ返します。 |
| sp_OASetProperty |
| OLE オブジェクトのプロパティ値に新しい値を設定します。 ■構文 sp_OASetProperty objecttoken , propertyname , newvalue [ , index... ] ■引数 objecttoken 以前に sp_OACreate で作成した OLE オブジェクトのオブジェクト トークンを指定します。 propertyname 新しい値を設定する OLE オブジェクトのプロパティ名を指定します。 newvalue プロパティの新しい値を指定します。指定する場合は、適切なデータ型の値にする必要があります。 index インデックス パラメータです。 指定する場合、index は適切なデータ型の値にする必要があります。 プロパティの一部はパラメータを持っています。 このようなプロパティをインデックス付きプロパティと呼び、そのパラメータをインデックス パラメータと呼びます。 1 つのプロパティが複数のインデックス パラメータを持つことができます。 ■戻り値 成功した場合は 0、失敗した場合は OLE オートメーション オブジェクトによって返される HRESULT の 0 以外の整数値を返します。 |
| sp_OAStop |
| サーバー全体の OLE オートメーション ストアド プロシージャの実行環境を停止します。 ■構文 sp_OAStop ■引数 なし。 ■戻り値 成功した場合は 0 を、失敗した場合は OLE オートメーション オブジェクトによって返される HRESULT の 0 以外の整数値をそれぞれ返します。 |
| ループ内でExcel(エクセル)に書き出す際の注意点 |
| ループ内でExcel(エクセル)に書き込む場合は注意が必要です。 VC++などではCOMはプログラムの初めに一度だけ初期化し、必要のなくなって時点で終了させますが、SP(ストアドプロシージャ)内ではこれが通じません。 例) COMの初期化 ループ開始 Excel(エクセル)操作 ループ終了 COMの終了 上記のようなコーディングではOAエラーが発生します。(なぜだかは不明。) 以下のようなコーディングでこれを回避可能です。 例) ・・・ ループ開始 COMの初期化 Excel(エクセル)操作 COMの終了 ループ終了 ・・・ |
| その1.指定セルへの「シート数指定」、「書込」、「罫線」、「変色」、「幅・高さ」、「結合」、「画像」、「寄せ」、「ハイパーリンク」、「シート名変更」 |
| --///////////////////////////////////////////////////////////////////////////////////////// -- ファイル名 :ExcelTest1 -- 概要 : -- 指定セルへの -- 「シート数指定」、「書込」、「罫線」、「変色」、「幅・高さ」、「結合」、「画像」、「寄せ」、「ハイパーリンク」、「シート名変更」 -- を行う。 -- -- 戻り値 : -- :0:正常終了 -- :0以外:異常終了 -- -- SP存在サーバ名:BLUE-TRANSPARENCY -- 参照テーブル :なし -- 作成テーブル :なし -- 参照SP : -- master.dbo.xp_cmdshell -- sp_OACreate, sp_OAGetProperty, sp_OAMethod, sp_OASetProperty, sp_OAGetProperty, sp_OAGetErrorInfo, sp_OADestroy -- -- 作成日:2006/10/18 asuka -- コピーライト:BLUE-TRANSPARENCY〜限りなく透明に近いブルー〜 --///////////////////////////////////////////////////////////////////////////////////////// CREATE PROCEDURE [dbo].[ExcelTest1] AS -- //////////////////////////////////////////////////////////////////////////////////// -- 初期化 -- //////////////////////////////////////////////////////////////////////////////////// SET NOCOUNT ON SET ANSI_WARNINGS OFF SET ANSI_NULLS ON -- //////////////////////////////////////////////////////////////////////////////////// -- 変数とカーソルの宣言 -- //////////////////////////////////////////////////////////////////////////////////// DECLARE @ChvFolderPath VARCHAR(100) -- エクセル格納先フォルダフルパス DECLARE @ChvExcelFileName VARCHAR(100) -- エクセルファイルフルパス名 DECLARE @IntObject INTEGER -- オブジェクトの引数 DECLARE @IntHResult INTEGER -- オブジェクトの戻値 DECLARE @ChvProperty VARCHAR(255) -- DECLARE @return VARCHAR(255) -- DECLARE @return_int INTEGER -- DECLARE @objResults INTEGER -- sp_OAMethodのOUT PUT値 DECLARE @col VARCHAR(100) -- 未使用 DECLARE @row VARCHAR(100) -- 未使用 DECLARE @num_cols INTEGER -- セレクトしたテーブルのレコードセットの行(カラム)数 DECLARE @num_rows INTEGER -- セレクトしたテーブルのレコードセットの列数 DECLARE @resultados VARCHAR(255) -- DECLARE @pba VARCHAR(255) -- DECLARE @indRow INTEGER -- 取得したレコードセットの何行目から書込むか指定 1行目が0にあたる DECLARE @indColumn INTEGER -- DECLARE @ObjExcel INTEGER -- エクセルオブジェクト DECLARE @WorkBooks INTEGER -- エクセルワークブックスオブジェクト DECLARE @WorkBook INTEGER -- エクセルワークブックオブジェクト DECLARE @offrow INTEGER -- DECLARE @offcolumn INTEGER -- DECLARE @rango VARCHAR(100) -- DECLARE @Range INTEGER -- セルのプロパティオブジェクト DECLARE @ChvQuerry VARCHAR(255) -- SQLクエリ文字列 -- //////////////////////////////////////////////////////////////////////////////////// -- フォルダ作成 - エクセル格納先 -- //////////////////////////////////////////////////////////////////////////////////// -- ファイル名作成 DECLARE @ChvYYYYMMDD VARCHAR(10) DECLARE @ChvYYYY VARCHAR(8) DECLARE @ChvMM VARCHAR(8) DECLARE @ChvDD VARCHAR(8) SET @ChvYYYY = DATENAME( year, GETDATE() ) SET @ChvMM = DATENAME( month, GETDATE() ) SET @ChvDD = DATENAME( day, GETDATE() ) SET @ChvDD = '0' + @ChvDD SET @ChvDD = RIGHT( @ChvDD, 2 ) SET @ChvYYYYMMDD = @ChvYYYY + @ChvMM + @ChvDD -- フォルダパス設定 SET @ChvFolderPath = 'C:\'+@ChvYYYYMMDD+'' -- DOSコマンド DECLARE @ChvCmd VARCHAR(255) DECLARE @IntRet INTEGER -- ディレクトリ存在チェック SET @ChvCmd = ' dir ' + @ChvFolderPath + ' /b' EXEC @IntRet = master.dbo.xp_cmdshell @ChvCmd, no_output IF @@ERROR != 0 BEGIN PRINT 'フォルダ存在チェックでエラーが発生しました。' RETURN @IntRet END -- ディレクトリが存在しない場合 IF @IntRet != 0 BEGIN -- ディレクトリ作成 SET @ChvCmd = ' md ' + @ChvFolderPath + '' EXEC @IntRet = master.dbo.xp_cmdshell @ChvCmd, no_output IF @@ERROR != 0 BEGIN PRINT 'ディレクトリの作成に失敗しました。@@ERROR != 0' RETURN @IntRet END IF @IntRet != 0 BEGIN PRINT 'ディレクトリの作成に失敗しました。@IntRet != 0' END END -- エクセルファイル名作成(フルパス) SET @ChvExcelFileName = ''+@ChvFolderPath+'\ExcelTest1.xls' -- //////////////////////////////////////////////////////////////////////////////////// -- オブジェクト生成 -- //////////////////////////////////////////////////////////////////////////////////// EXEC @IntHResult = sp_OACreate 'SQLDMO.SQLServer', @IntObject OUT IF @IntHResult <> 0 BEGIN PRINT 'sp_OACreateに失敗しました。' RETURN @IntHResult END -- //////////////////////////////////////////////////////////////////////////////////// -- メソッドコール - sp_OAMethod -- //////////////////////////////////////////////////////////////////////////////////// -- データベースサーバ接続 EXEC @IntHResult = sp_OAMethod @IntObject, 'Connect', NULL,'FUJICHAWA', 'sa','' IF @IntHResult <> 0 BEGIN PRINT 'sp_OAMethodに失敗しました。(データベースサーバ接続失敗)' RETURN @IntHResult END -- 接続確認 EXEC @IntHResult = sp_OAMethod @IntObject, 'VerifyConnection', @return OUT IF @IntHResult <> 0 BEGIN PRINT 'sp_OAMethodに失敗しました。(データベースサーバ接続確認失敗)' RETURN @IntHResult END -- //////////////////////////////////////////////////////////////////////////////////// -- エクセル書込み - セル指定 -- //////////////////////////////////////////////////////////////////////////////////// -- エクセルオブジェクト生成 EXEC @IntHResult = sp_OACreate 'Excel.Application', @ObjExcel OUT -- エクセルにワークブックプロパティ取得 EXEC @IntHResult = sp_OAGetProperty @ObjExcel ,'WorkBooks', @WorkBooks OUT --シート数設定 EXEC @IntHResult = sp_OASetProperty @WorkBooks,'Application.SheetsInNewWorkbook','5' -- エクセルワークブックのアッドプロパティ取得 EXEC @IntHResult = sp_OAGetProperty @WorkBooks,'Add', @WorkBook OUT EXEC @IntHResult = sp_OAMethod @WorkBooks,'ActiveSheet.Hyperlinks.Add',NULL,'Selection','"http://www.yahoo.co.jp"',NULL,NULL,'"Yahoo"' -- 指定セル書込み EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A1")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', 'ExcelTest3 - 指定したセルに書き込み' EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A2")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', 'Copyright Fujisaw Yohei' EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A3")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', 'Copyright (C)2003 Video Research Netcom Ltd. All Rights Reserved.' -- 太線 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A4")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', '太線' EXEC @IntHResult = sp_OASetProperty @Range,'Font.Bold', 'TRUE' -- 罫線 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("B7")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Borders(7).LineStyle', '1' EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("C7")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Borders(8).LineStyle', '1' EXEC @IntHResult = sp_OASetProperty @Range,'Borders(9).LineStyle', '1' -- 色変更 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("B10")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Interior.ColorIndex', '3' -- 幅変更 -- 幅 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("B:B")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'ColumnWidth', '22' -- 高 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("9:9")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'RowHeight', '22' -- セルの結合 - TRUE:結合する FALSE:結合しない -- MergeだとTRUEでもFALSEでも結合してしまう。 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("D4:E6")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'MergeCells', 'TRUE' -- 画像 - sp_OASetPropertyにエクセルオブジェクト指定のこと EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("F3").Select',@Range OUT EXEC @IntHResult = sp_OASetProperty @ObjExcel,'ActiveSheet.Pictures.Insert("C:\dora6.gif").Select', '1' -- 寄せ -- 左寄せ EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A14")', @Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', '左寄せ' EXEC @IntHResult = sp_OASetProperty @Range,'HorizontalAlignment', '2' -- 右寄せ EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A15")', @Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', '右寄せ' EXEC @IntHResult = sp_OASetProperty @Range,'HorizontalAlignment', '4' -- 中央寄せ EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("A16")', @Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', '中央' EXEC @IntHResult = sp_OASetProperty @Range,'HorizontalAlignment', '3' */ -- ハイパーリンク EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("C22")',@Range OUT EXEC @IntHResult = sp_OASetProperty @Range,'Value', '=HYPERLINK( "http://www.yahoo.co.jp" , "いけてる?" )' -- ↓駄目なハイパーリンク --EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Range("C22")',@Range OUT --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp', '', '', '', '' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp', '', '' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp', '' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, '"http://www.yahoo.co.jp","http://www.goo.ne.jp"' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp,http://www.goo.ne.jp' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', 'http://www.goo.ne.jp', 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp', '', '', '', '' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp', '', '' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp', '' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'ActiveSheet.Hyperlinks.Add', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', @return OUT, '"http://www.yahoo.co.jp","http://www.goo.ne.jp"' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp,http://www.goo.ne.jp' --EXEC @IntHResult = sp_OAMethod @ObjExcel, 'Hyperlinks', 'http://www.goo.ne.jp', 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @Range, 'Hyperlinks', @return OUT, 'http://www.yahoo.co.jp', 'http://www.yahoo.co.jp' --EXEC @IntHResult = sp_OAMethod @IntObject, 'Connect', NULL,'FUJICHAWA', 'sa','' -- デバック /* IF @IntHResult <> 0 -- Fehlerbehandlung BEGIN DECLARE @verbindung INTEGER DECLARE @quelle VARCHAR(255) DECLARE @beschreibung VARCHAR(255) DECLARE @dbname VARCHAR(255) EXEC sp_OAGetErrorInfo @verbindung, @quelle OUTPUT, @beschreibung OUTPUT RAISERROR ( 'HyperLink %s: %s', 10 , -1, @quelle, @beschreibung) END */ --objExcelSheet.Hyperlinks.Add objExcelSheet.Cells(5,2),"http://www.yahoo.co.jp","","http://www.yahoo.co.jpにリンク","Yahoo" -- シート名変更 EXEC @IntHResult = sp_OAGetProperty @ObjExcel,'Sheets("Sheet1")' EXEC @IntHResult = sp_OASetProperty @ObjExcel, 'Sheets("Sheet1").Name', 'ExcelTest3' -- //////////////////////////////////////////////////////////////////////////////////// -- エクセルファイル作成 -- //////////////////////////////////////////////////////////////////////////////////// -- エクセルファイル破棄 SELECT @pba = "EXEC master..xp_cmdshell 'del " + @ChvExcelFileName + "', no_output" EXEC(@pba) -- エクセルファイル保存 SELECT @pba = 'SaveAs("' + @ChvExcelFileName + '")' EXEC @IntHResult = sp_OAMethod @WorkBook, @pba EXEC @IntHResult = sp_OAMethod @WorkBook, 'Close' -- //////////////////////////////////////////////////////////////////////////////////// -- オブジェクト破棄 -- //////////////////////////////////////////////////////////////////////////////////// EXEC @IntHResult = sp_OADestroy @ObjExcel EXEC @IntHResult = sp_OADestroy @IntObject GO |
| その2.指定セルへの指定したテーブル名の結果を書込み |
| --///////////////////////////////////////////////////////////////////////////////////////// -- ファイル名 :ExcelTest2 -- 概要 : -- 指定セルへの指定セルへの指定したテーブル名の結果を書込み -- -- 戻り値 : -- :0:正常終了 -- :0以外:異常終了 -- -- SP存在サーバ名:BLUE-TRANSPARENCY -- 参照テーブル :なし -- 作成テーブル :なし -- 参照SP : -- master.dbo.xp_cmdshell -- sp_OACreate, sp_OAGetProperty, sp_OAMethod, sp_OASetProperty, sp_OAGetProperty, sp_OAGetErrorInfo, sp_OADestroy -- -- 作成日:2006/10/18 asuka -- コピーライト:BLUE-TRANSPARENCY〜限りなく透明に近いブルー〜 --///////////////////////////////////////////////////////////////////////////////////////// CREATE PROCEDURE [dbo].[ExcelTest2] AS -- //////////////////////////////////////////////////////////////////////////////////// -- 初期化 -- //////////////////////////////////////////////////////////////////////////////////// SET NOCOUNT ON SET ANSI_WARNINGS OFF SET ANSI_NULLS ON -- //////////////////////////////////////////////////////////////////////////////////// -- 変数とカーソルの宣言 -- //////////////////////////////////////////////////////////////////////////////////// DECLARE @ChvFolderPath VARCHAR(100) -- エクセル格納先フォルダフルパス DECLARE @ChvExcelFileName VARCHAR(100) -- エクセルファイルフルパス名 DECLARE @IntObject INTEGER -- オブジェクトの引数 DECLARE @IntHResult INTEGER -- オブジェクトの戻値 DECLARE @ChvProperty VARCHAR(255) -- DECLARE @return VARCHAR(255) -- DECLARE @return_int INTEGER -- DECLARE @objResults INTEGER -- sp_OAMethodのOUT PUT値 DECLARE @col VARCHAR(100) -- 未使用 DECLARE @row VARCHAR(100) -- 未使用 DECLARE @num_cols INTEGER -- セレクトしたテーブルのレコードセットの行(カラム)数 DECLARE @num_rows INTEGER -- セレクトしたテーブルのレコードセットの列数 DECLARE @resultados VARCHAR(255) -- DECLARE @pba VARCHAR(255) -- DECLARE @indRow INTEGER -- 取得したレコードセットの何行目から書込むか指定 1行目が0にあたる DECLARE @indColumn INTEGER -- DECLARE @ObjExcel INTEGER -- エクセルオブジェクト DECLARE @WorkBooks INTEGER -- エクセルワークブックスオブジェクト DECLARE @WorkBook INTEGER -- エクセルワークブックオブジェクト DECLARE @offrow INTEGER -- DECLARE @offcolumn INTEGER -- DECLARE @rango VARCHAR(100) -- DECLARE @Range INTEGER -- セルのプロパティオブジェクト DECLARE @ChvQuerry VARCHAR(255) -- SQLクエリ文字列 -- //////////////////////////////////////////////////////////////////////////////////// -- フォルダ作成 - エクセル格納先 -- //////////////////////////////////////////////////////////////////////////////////// -- ファイル名作成 DECLARE @ChvYYYYMMDD VARCHAR(10) DECLARE @ChvYYYY VARCHAR(8) DECLARE @ChvMM VARCHAR(8) DECLARE @ChvDD VARCHAR(8) SET @ChvYYYY = DATENAME( year, GETDATE() ) SET @ChvMM = DATENAME( month, GETDATE() ) SET @ChvDD = DATENAME( day, GETDATE() ) SET @ChvDD = '0' + @ChvDD SET @ChvDD = RIGHT( @ChvDD, 2 ) SET @ChvYYYYMMDD = @ChvYYYY + @ChvMM + @ChvDD -- フォルダパス設定 SET @ChvFolderPath = 'C:\'+@ChvYYYYMMDD+'' -- DOSコマンド DECLARE @ChvCmd VARCHAR(255) DECLARE @IntRet INTEGER -- ディレクトリ存在チェック SET @ChvCmd = ' dir ' + @ChvFolderPath + ' /b' EXEC @IntRet = master.dbo.xp_cmdshell @ChvCmd, no_output IF @@ERROR != 0 BEGIN PRINT 'フォルダ存在チェックでエラーが発生しました。' RETURN @IntRet END -- ディレクトリが存在しない場合 IF @IntRet != 0 BEGIN -- ディレクトリ作成 SET @ChvCmd = ' md ' + @ChvFolderPath + '' EXEC @IntRet = master.dbo.xp_cmdshell @ChvCmd, no_output IF @@ERROR != 0 BEGIN PRINT 'ディレクトリの作成に失敗しました。@@ERROR != 0' RETURN @IntRet END IF @IntRet != 0 BEGIN PRINT 'ディレクトリの作成に失敗しました。@IntRet != 0' END END -- エクセルファイル名作成(フルパス) SET @ChvExcelFileName = ''+@ChvFolderPath+'\ExcelTest2.xls' -- //////////////////////////////////////////////////////////////////////////////////// -- オブジェクト生成 -- //////////////////////////////////////////////////////////////////////////////////// EXEC @IntHResult = sp_OACreate 'SQLDMO.SQLServer', @IntObject OUT IF @IntHResult <> 0 BEGIN PRINT 'sp_OACreateに失敗しました。' RETURN @IntHResult END -- //////////////////////////////////////////////////////////////////////////////////// -- メソッドコール - sp_OAMethod -- //////////////////////////////////////////////////////////////////////////////////// -- データベースサーバ接続 EXEC @IntHResult = sp_OAMethod @IntObject, 'Connect', NULL,'BLUE-TRANSPARENCY', 'sa','' IF @IntHResult <> 0 BEGIN PRINT 'sp_OAMethodに失敗しました。(データベースサーバ接続失敗)' RETURN @IntHResult END -- 接続確認 EXEC @IntHResult = sp_OAMethod @IntObject, 'VerifyConnection', @return OUT IF @IntHResult <> 0 BEGIN PRINT 'sp_OAMethodに失敗しました。(データベースサーバ接続確認失敗)' RETURN @IntHResult END -- //////////////////////////////////////////////////////////////////////////////////// -- エクセル書込み - テーブル内容 -- //////////////////////////////////////////////////////////////////////////////////// -- エクセルオブジェクト生成 EXEC @IntHResult = sp_OACreate 'Excel.Application', @ObjExcel OUT -- エクセルにワークブックプロパティ取得 EXEC @IntHResult = sp_OAGetProperty @ObjExcel ,'WorkBooks', @WorkBooks OUT --シート数設定 EXEC @IntHResult = sp_OASetProperty @WorkBooks,'Application.SheetsInNewWorkbook','5' -- エクセルワークブックのアッドプロパティ取得 EXEC @IntHResult = sp_OAGetProperty @WorkBooks,'Add', @WorkBook OUT -- 結果セットのあるクエリーを実行 - ExecuteWithResults SELECT @ChvQuerry='Select * from ProcedureDB..VariousTypeTable01 ' SELECT @resultados= 'ExecuteWithResults("' + @ChvQuerry +'")' EXEC @IntHResult = sp_OAMethod @IntObject, @resultados, @objResults OUT -- 取得した結果セットのテーブルの行(カラム)数取得 EXEC @IntHResult = sp_OAGetProperty @objResults, 'Columns' , @num_cols OUT IF @IntHResult <> 0 BEGIN EXEC sp_displayoaerrorinfo @IntObject, @IntHResult RETURN END -- 取得した結果セットのテーブルの列数取得 EXEC @IntHResult = sp_OAGetProperty @objResults, 'Rows' , @num_rows OUT PRINT ' Rows' PRINT @num_rows IF @IntHResult <> 0 BEGIN PRINT'結果セット取得失敗。' RETURN @IntHResult END -- デバッグ:行数、列数表示 SELECT @num_cols AS Num_Columns, @num_rows AS Num_Rows -- 指定したテーブルの行、列の文字列を取得 - 'GetColumnString ', @col OUT, 列, 行 EXEC @IntHResult = sp_OAMethod @objResults, 'GetColumnString',@resultados OUT, 1 , 1 --PRINT '1:1行1列目' PRINT '1-1' PRINT @resultados EXEC @IntHResult = sp_OAMethod @objResults, 'GetColumnString',@resultados OUT, 2 , 2 --PRINT '2:2行2列目' PRINT '2-2' PRINT @resultados EXEC @IntHResult = sp_OAMethod @objResults, 'GetColumnString',@resultados OUT, 3 , 3 --PRINT '3:3行3列目' PRINT '3-3' PRINT @resultados EXEC @IntHResult = sp_OAMethod @objResults, 'GetColumnString',@resultados OUT, 4 , 4 --PRINT '4:4行4列目' PRINT '4-4' PRINT @resultados EXEC @IntHResult = sp_OAMethod @objResults, 'GetColumnString',@resultados OUT, 5, 5 --PRINT '5:5行5列目' PRINT '5-5' PRINT @resultados SELECT @offrow = 0 SELECT @offcolumn = 1 SELECT @indRow = 0 -- 取得したレコードセットの何行目から書込むか指定 1行目が0にあたる -- 行 WHILE( @indRow <= @num_rows ) BEGIN -- テーブルの列(カラム数)指定 SELECT @indColumn = 1 -- 1指定 WHILE ( @indColumn <= @num_cols ) BEGIN EXEC @IntHResult = sp_OAMethod @objResults, 'GetColumnString', @pba OUT, @indRow, @indColumn EXEC @IntHResult = sp_OASetProperty @Range,'Value', @pba SELECT @pba = RTRIM(@pba) EXEC @IntHResult = sp_OAGetProperty @Range,'Offset',@Range OUT ,@offrow , @offcolumn -- 列のインクリメント SELECT @indColumn = @indColumn + 1 END -- 'Segundo While' SELECT @offrow=0 SELECT @offcolumn=1 SELECT @indRow=@indRow+1 SELECT @rango = 'Range("A' + LTRIM(str(@indRow))+ '")' EXEC @IntHResult= sp_OAGetProperty @ObjExcel, @rango, @Range OUT END -- //////////////////////////////////////////////////////////////////////////////////// -- エクセルファイル作成 -- //////////////////////////////////////////////////////////////////////////////////// -- エクセルファイル破棄 SELECT @pba = "EXEC master..xp_cmdshell 'del " + @ChvExcelFileName + "', no_output" EXEC(@pba) -- エクセルファイル保存 SELECT @pba = 'SaveAs("' + @ChvExcelFileName + '")' EXEC @IntHResult = sp_OAMethod @WorkBook, @pba EXEC @IntHResult = sp_OAMethod @WorkBook, 'Close' -- //////////////////////////////////////////////////////////////////////////////////// -- オブジェクト破棄 -- //////////////////////////////////////////////////////////////////////////////////// EXEC @IntHResult = sp_OADestroy @ObjExcel EXEC @IntHResult = sp_OADestroy @IntObject PRINT'End' GO |
| 考察 |
| 恐ろしいいくらいにCPUとメモリを使用します。 ASPとの連携の場合は、ASP側にExcel(エクセル)ファイルを作らせるのが吉のように思えます。 ループ内で行数を変えてExcel(エクセル)に書き込む場合は、最大行数(6万5536行)を監視する処理を追加する必要があります。 超える場合は別シート、あるいは別ファイルに記載するようにするべきでしょう。 バッチ処理にてSP(ストアドプロシージャ)で処理しなければならない仕事だったので作ってみたけれども、 多分SP(ストアドプロシージャ)はCOM操作に不向きなんだと思われます。 ちなみに、原因が不明で特定の行数から書き込めない現象なども発生しました。 メモリ増設で回避しましたが、他にも問題はありそうです。 毎回COMを解放してるのに何ででしょう・・・ |
| ■リンクサーバ | |||||||||
| リンクサーバ | |||||||||
| リンクサーバとは、(SP、クエリなどから)異なるサーバ間でテーブルの参照、挿入、削除などを行う際に相手側のサーバを登録しておく必要があります。 例:サーバSCOREからサーバSCORE-BACK-DBをリンクサーバに登録 1.EnterprISe ManagerのSCOREからセキュリティ→リンクサーバで右クリック→新規リンクサーバを選択 ![]() 2.[全般]タブにてリンクサーバにSCORE-BACK-DBとサーバ名記載。サーバの種類をSQL Serverに設定。 [セキュリティ]タブにて次のセキュリティコンテキストを使用するを選択し、ログインIDとパスワードを設定します。
|
|||||||||
| ■クロス集計 |
| 行と列を入れ替える |
| 行と列を入れ替える集計 Accessではクロス集計用の命令があるが、SQLServerには無い。そのため、CASEとSUMを使います。 CASEを使うためには値を決めておく必要があるため、Accessのように全部の行列を入れ替えるということは出来ません。 SQLServerのクロスタブレポートの項から抜粋。 例)
以下のような Pivot というテーブルがあり、毎年のQuarterごとの集計を出したい場合。
|
| ■上位レコード取得 |
| TopとSET ROWCOUNT |
|
上位10件を取得したい場合 例2) SET rowcount を使う。SET rowcountの場合、10のところに@IntNum等が使える。ただし、SET
rowcount 0 で元に戻すのを忘れない事 |
| ■ランキング |
| 振り方 |
| TABLE1(ID int,数値 int,Ranking int)というテーブルがあります。 このテーブルにID(ユニーク)と数値が入っていたときの数値で比べたときのランキングを求めて、updateするクエリを以下に示します。 update #tmpAnalyze00_01_MAIN SET Ranking = (SELECT count(T1.数値) FROM TABLE1 as T1 WHERE T1.数値 > TABLE1.数値) +1 ランキングを出すだけのSELECT文は以下のようになります。 SELECT ID,数値, (SELECT count(T1.数値) FROM TABLE1 as T1 WHERE T1.数値 > TABLE1.数値) +1 as Rank FROM TABLE1 ORDER BY Rank |
| ■ソート |
| カンマ区切り文字列のソート |
| '3,6,2,5,12' という番号をカンマ区切りにした文字列を'2,3,5,6,12'に並べ替える方法 '3,6,2,5,12'をカンマ毎に区切って、一時テーブルに入れます。 一時テーブルを番号でORDER BY して SELECTします。そうすると 2,3,5,6,12の順で結果が取れます。そのSELECT分をカーソルでまわして 連結すれば、'3,6,2,5,12'という文字列が作れます。 例) 下の「カンマ区切り文字列からトークンを一つ取り出すSP」を作成してからこのクエリを実行してください。 DECLARE @IntPos int SET @INtPos = 0 DECLARE @ChvToken1 CREATE TABLE #tmpSortTABLE (int n) WHILE 1>0 BEGIN EXEC scoGetToken '3,6,2,5,12', @IntPos OUTPUT, @ChvToken1 OUTPUT IF @ChvToken1 IS NULL -- これ以上トークンがない BREAK INSERT INTO #tmpSortTABLE CONVERT(int,@ChvToken) END SELECT * FROM #tmpSortTABLE ORDER BY n --このSELECT分をカーソルでまわして n を連結すればソートされた文字列になります。 --カーソルについては、Tipsの024か参考文献を参照してください。 カンマ区切り文字列からトークンを一つ取り出すSP /****************************************************************************** ** プロシジャ名:scoGetToken ** 説明 :引数で渡されたカンマ区切り文字列からトークンを1つ取り出します ** : ** :引数の@IntPosはトークンを切り出す位置です。たとえば0が指定さ ** :れた場合には先頭のトークンが切り出されます。切り出しが完了する ** :とこの変数は自動的に更新されます。(ファイルポインタみたいなも ** :のですね) ******************************************************************************/ CREATE PROCEDURE dbo.scoGetToken ( @ChvString varchar(256), -- (I) カンマ区切り文字列 @IntPos int OUTPUT, -- (I/O) トークンを切り出す位置 @ChvToken varchar(256) OUTPUT -- (O) 切り出したトークン ) AS ------------------------------------------------------------------------------- -- 初期化 ------------------------------------------------------------------------------- SET NOCOUNT ON DECLARE @ChvTmp varchar(2) DECLARE @IntStartPos int DECLARE @IntLen int SET @IntStartPos = @IntPos SET @IntLen = LEN( @ChvString ) ------------------------------------------------------------------------------- -- 入力値チェック ------------------------------------------------------------------------------- SET @ChvToken = NULL IF @IntPos >= @IntLen RETURN ------------------------------------------------------------------------------- -- トークンの切り出し ------------------------------------------------------------------------------- SET @ChvToken = '' WHILE 1 > 0 BEGIN SET @ChvTmp = LEFT( RIGHT( @ChvString, @IntLen - @IntPos ) , 1 ) IF ( @ChvTmp IS NULL ) or ( @ChvTmp = '' ) BEGIN -- 文字列の最後に達した RETURN END SET @IntPos = @IntPos + 1 IF @ChvTmp = ',' BEGIN -- カンマに達した RETURN END SET @ChvToken = @ChvToken + @ChvTmp END -- 無限ループなので、このRETURNは通らない。 RETURN -- EOF -- |
| ■待機 |
| 一定時間待機(WAIT FOR) |
| WAITFOR DELAY '000:00:05' --5秒間待機します。 WAITFOR TIME '14:30:00' -- 14時30分まで待機します。 |
| ■サーバ名 |
| [-]がある場合 |
|
クエリからBLUE-TRANSPARENCY-DBなど[-]のあるサーバに接続した場合。 |
| ■拡張SP(ストアドプロシージャ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 拡張SP(ストアドプロシージャ)について | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 拡張ストアド プロシージャでは、C 言語などのプログラミング言語で独自の外部ルーチンを作成することができます。 拡張ストアド プロシージャは、ユーザーには通常のストアド プロシージャのように見え、同じ方法で実行されます。 データベース クエリは、拡張ストアド プロシージャにデータを渡し、その拡張ストアド プロシージャは結果とリターン ステータスを返します。 SQL Server に含まれている標準の拡張ストアド プロシージャには、たとえば以下のような電子メール機能を提供するものがあります。 ・SQL メール クライアント セッションを開始する xp_startmail ・電子メールまたはページを送信する xp_sendmail |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "文字のある文字列をバルクインサートする | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ■はじめに Transact-SQLのSP内でファイルをテーブルにバルクインサートする際、文字列に "がある場合、bcpコマンドやBULK INSERTコマンドでは判断出来ません。 bcpコマンドやBULK INSERTコマンドで"文字をテーブルに挿入しようとするとエラーで止まります。 C(C++、VC++)言語では"文字の挿入が認められているため、C++でテーブルへの挿入用DLLを作成し、SPからDLL内の関数をコールさせて実現させます。 ■サンプルの仕様 ・概要 指定したファイルを指定したテーブルに挿入します。 ・拡張ストアドプロシージャ名 xp_SPEX ・拡張ストアドプロシージャの引数
■ポイント SP(ストアドプロシージャ)内で宣言されている型がC++では何に対応するかがポイントになります。 正直DATETIME型の扱いは非常に厄介です。 ■拡張SP(ストアドプロシージャ)をコールする側(SQ)のクエリのソースです。 --///////////////////////////////////////////////////////////////////////////////////// -- 拡張ストアドプロシージャ --///////////////////////////////////////////////////////////////////////////////////// --///////////////////////////////////////////////////////////////////////////////////// -- 登録 -- 登録は一度だけ実行します。 --sp_addextendedproc 'xp_SPEX', 'C:\Program Files\Microsoft SQL Server\MSSQL\Binn\xp_SPEX.dll' --///////////////////////////////////////////////////////////////////////////////////// -- 変数 DECLARE @IntErrorCode INTEGER -- 戻値 DECLARE @ChvServerName VARCHAR(1000) -- 1.CSVIn挿入先SQLサーバ名 DECLARE @ChvDBName VARCHAR(1000) -- 2.CSVIn挿入先SQLデータベース名 DECLARE @ChvOwnerName VARCHAR(1000) -- 3.CSVIn挿入先SQLオーナー名 DECLARE @ChvTableName VARCHAR(1000) -- 4.CSVIn挿入先SQLテーブル名 DECLARE @ChvID VARCHAR(1000) -- 5.CSVIn挿入先ログインID DECLARE @ChvPW VARCHAR(1000) -- 6.CSVIn挿入先ログインPW DECLARE @ChvInsertFileName VARCHAR(1000) -- 7.CSVInファイルのフルパス DECLARE @DtmInsertDate DATETIME -- 8.CSVInのインサートデート ■注意:この値が空でない場合:ファイルから読込んだ1行にこの値を足してインサート DECLARE @IntSkipFirstRowFlg INTEGER -- 9.CSVInファイルの初めの1行目をSkipするか 0:しない 1:する DECLARE @ChSkipFirstLetter CHAR(1) -- 10.CSVInファイルの1行目の初めの文字が指定した文字の場合はスキップ DECLARE @ChvLogFilePath VARCHAR(1000) -- 11.拡張ストアドプロシージャのログ出力先 DECLARE @ChvErrorMessage VARCHAR(1000) -- 12.エラーメッセージ(出力パラメータ) DECLARE @IntDebug INTEGER -- 13.デバッグ 1:デバッグ 0しない -- 変数初期値設定 SET @IntErrorCode = -1 SET @ChvServerName = 'BLUE-TRANSPARENCY' SET @ChvDBName = 'TestDB' SET @ChvOwnerName = 'dbo' SET @ChvTableName = 'TestTable' SET @ChvID = 'sa' SET @ChvPW = '' SET @ChvInsertFileName = 'C:\InsertFile.csv' SET @DtmInsertDate = '2006-10-18' SET @IntSkipFirstRowFlg = 1 --この値が空の場合:ファイルから読込んだ1行をそのままインサートします。 SET @ChSkipFirstLetter = '#' SET @ChvLogFilePath = 'C:\LOG\' SET @ChvErrorMessage = '' SET @IntDebug = 1 --///////////////////////////////////////////////////////////////////////////////////// -- 実行 EXEC @IntErrorCode = xp_SPEX @ChvServerName, -- 1 - INPUT @ChvDBName, -- 2 - INPUT @ChvOwnerName, -- 3 - INPUT @ChvTableName, -- 4 - INPUT @ChvID, -- 5 - INPUT @ChvPW, -- 6 - INPUT @ChvInsertFileName, -- 7 - INPUT @DtmInsertDate, -- 8 - INPUT @IntSkipFirstRowFlg, -- 9 - INPUT @ChSkipFirstLetter, -- 10 - INPUT @ChvLogFilePath, -- 11 - INPUT @ChvErrorMessage OUTPUT, -- 12 - OUTPUT @IntDebug -- 13 - INPUT -- 実行後の変数 PRINT '■■■ 実行後の変数 ■■■' PRINT '@IntErrorCode='+CAST( @IntErrorCode AS CHAR )+' ' PRINT '@ChvServerName='+@ChvServerName+' ' PRINT '@ChvDBName='+@ChvDBName+' ' PRINT '@ChvOwnerName='+@ChvOwnerName+' ' PRINT '@ChvTableName='+@ChvTableName+' ' PRINT '@ChvID='+@ChvID+' ' PRINT '@ChvPW='+@ChvPW+' ' PRINT '@ChvInsertFileName='+@ChvInsertFileName+' ' PRINT '@IntSkipFirstRowFlg='+CAST( @IntSkipFirstRowFlg AS CHAR )+' ' PRINT '@ChSkipFirstLetter='+@ChSkipFirstLetter+' ' PRINT '@ChvLogFilePath='+@ChvLogFilePath+' ' PRINT '@ChvErrorMessage='+@ChvErrorMessage+' ' PRINT '@IntDebug='+CAST( @IntDebug AS CHAR )+' ' --///////////////////////////////////////////////////////////////////////////////////// -- 削除 --sp_dropextendedproc 'xp_SPEX' --///////////////////////////////////////////////////////////////////////////////////// -- DLLアンロード DBCC xp_SPEX (FREE) --sp_helpextendedproc ■xp_SPEX.DLLのソースです //////////////////////////////////////////////////////////////////////////////////////////// // DLL名:xp_SPEX // 概要:Transact-SQLのSP内でファイルをテーブルにバルクインサートする際、文字列に // "があることをbcpやBULK INSERTコマンドでは判断できないため、このDLLが拡張ス // トアドプロシージャとして代替する。 // 処理対象ファイルの1行読込み、テーブルへインサート // // 戻値:正常時:XP_NOERROR 0 // 異常時:XP_ERROR 0 // ストアドプロシージャ側にもこの戻値が返る。Ex. EXEC @IntErrorCode = xp_SPEX ・・・ // // 周囲:インサートするCSVファイルの形式はCHAR、VARCHAR、DATETIMEは"で囲むこと。INT系は囲まないこと。 // // 参照テーブル:引数でもらうテーブル // // 拡張ストアドプロシージャ名:xp_SPEX // // 拡張ストアドプロシージャの引数: // 01:@ChvServerName INPUT - 処理対象サーバ名 // 02:@ChvDBName INPUT - 処理対象DB名 // 03:@ChvOwnerName INPUT - 処理対象DB名を所有するオーナ名(dbo) // 04:@ChvTableName INPUT - 処理対象テーブル名 // 05:@ChvID INPUT - 処理対象サーバのログインID(文字列(sa)) // 06:@ChvPW INPUT - 処理対象サーバのパスワード // 07:@ChvInsertFileName INPUT - 処理対象ファイルのフルパス // 08:@DtmInsertDate INPUT - 処理対象日 // 09:@IntSkipFirstRowFlg INPUT - 処理対象ファイルの最初の行をスキップするかしないか(1:スキップする 0:スキップしない) // 10:@ChSkipFirstLetter INPUT - 処理対象ファイルの1行目1文字目にこの引数でもらう文字があれば処理しない(#行は処理しない。) // 11:@ChvLogFilePath INPUT - このプロシージャが出すログファイル先パス(\で終わること。このプロシージャでは特にチェックしない。) // 12:@ChvErrorMessage OUTPUT - このプロシージャが出すエラーメッセージ // 13:@IntDebug INPUT - デバッグモード // // 作成日:2003/10/27 // 作成者:asuka // 履歴: //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// // ヘッダ //////////////////////////////////////////////////////////////////////////////////////////// #include <stdafx.h> #include "Cprocfuncs.h" #include "CReadFileLine.h" #include <Shlwapi.h> #pragma comment ( lib, "Shlwapi.lib" ) // ADO #import "C:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "EndOfFile") #include <ole2.h> #include <stdio.h> #include <conio.h> // Function declarations - マクロ inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);}; //////////////////////////////////////////////////////////////////////////////////////////// // 定義 //////////////////////////////////////////////////////////////////////////////////////////// #define XP_NOERROR 0 // 戻値:正常リターン値 - ストアドプロシージャ側と一致する #define XP_ERROR -1 // 戻値:異常リターン値 - ストアドプロシージャ側と一致する #define nNum 13 // ストアドプロシージャのパラメータの数 #define MODULENAME "xp_SPEX" // モジュール名 #define MODULEEXTD ".dll" // モジュールの拡張子 //////////////////////////////////////////////////////////////////////////////////////////// // 構造体 //////////////////////////////////////////////////////////////////////////////////////////// // インサート情報構造体 typedef struct structInsertInfo{ SRV_PROC *pSrvProc; TCHAR szServerName[BUF_SIZE]; // 01:@ChvServerName INPUT - 処理対象サーバ名 TCHAR szDBName[BUF_SIZE]; // 02:@ChvDBName INPUT - 処理対象DB名 TCHAR szOwnerName[BUF_SIZE]; // 03:@ChvOwnerName INPUT - 処理対象DB名を所有するオーナ名(dbo) TCHAR szTableName[BUF_SIZE]; // 04:@ChvTableName INPUT - 処理対象テーブル名 TCHAR szID[BUF_SIZE]; // 05:@ChvID INPUT - 処理対象サーバのログインID(文字列(sa)) TCHAR szPW[BUF_SIZE]; // 06:@ChvPW INPUT - 処理対象サーバのパスワード TCHAR szInsertFileName[BUF_SIZE]; // 07:@ChvInsertFileName INPUT - 処理対象ファイルのフルパス TCHAR szInsertDate[BUF_SIZE]; // 08:@DtmInsertDate INPUT - 処理対象日 INT nSkipFirstRowFlg; // 09:@IntSkipFirstRowFlg INPUT - 処理対象ファイルの最初の行をスキップするかしないか(1:スキップする 0:スキップしない) TCHAR szSkipFirstLetter[BUF_SIZE]; // 10:@ChSkipFirstLetter INPUT - 処理対象ファイルの1行目1文字目にこの引数でもらう文字があれば処理しない(#行は処理しない。) TCHAR szLogFilePath[BUF_SIZE]; // 11:@ChvLogFilePath INPUT - このプロシージャが出すログファイル先パス(\で終わること。このプロシージャでは特にチェックしない。) TCHAR szErrorMessage[BUF_SIZE]; // 12:@ChvErrorMessage OUTPUT - このプロシージャが出すエラーメッセージ INT nDebug; // 13:@IntDebug INPUT - デバッグモード } STRUCT_INSERTINFO; STRUCT_INSERTINFO InsertInfo; //////////////////////////////////////////////////////////////////////////////////////////// // プロトタイプ //////////////////////////////////////////////////////////////////////////////////////////// VOID PrintProviderError ( SRV_PROC *pSrvProc, CHAR* szErrorMsg ); // PrintProviderError - SQLサーバ側で発生したエラーを取得 VOID PrintUsageInfo( SRV_PROC *pSrvProc ); // PrintUsageInfo - ストアドプロシージャの使用方法が間違っているためクライアントに使用方法を伝える VOID ADOPrintProviderError( _ConnectionPtr pConnection ); // ADOPrintProviderError - ADO使用によるSQLサーバ側で発生したエラーを取得 VOID ADOPrintComError( _com_error &e ); // ADOPrintComError - COMエラー情報取得 INT InsertThreadMain( STRUCT_INSERTINFO* lpInsertInfo ); // ファイルから1行ずつテーブルへインサート - スレッドが使用する関数 INT InsertThreadMain2( STRUCT_INSERTINFO* pInsertInfo ); // ファイルから1行ずつテーブルへインサート - 通常の関数 //////////////////////////////////////////////////////////////////////////////////////////// // クラス //////////////////////////////////////////////////////////////////////////////////////////// // このプロシージャの処理を関数にしたクラス Cprocfuncs cProcFuncs; //////////////////////////////////////////////////////////////////////////////////////////// // グローバル変数 //////////////////////////////////////////////////////////////////////////////////////////// HANDLE _hThread; // スレッドハンドル DWORD _dwThreadID; // スレッドID HANDLE _hSemaphore; // セマフォアハンドル LONG _lSemaCount; // //////////////////////////////////////////////////////////////////////////////////////////// // プロシージャ //////////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif RETCODE __declspec(dllexport) xp_SPEX( SRV_PROC *pSrvProc ); #ifdef __cplusplus } #endif RETCODE __declspec(dllexport) xp_SPEX( SRV_PROC *pSrvProc ) { //////////////////////////////////////////////////////////////////////////////////////////// // proc開始 cLog->WriteLogFile( "■■■xp_SPEX開始■■■" ); //////////////////////////////////////////////////////////////////////////////////////////// // 変数 // ↓SPのパラメータを受取る変数 TCHAR szServerName[BUF_SIZE]; // 01:@ChvServerName INPUT - 処理対象サーバ名 TCHAR szDBName[BUF_SIZE]; // 02:@ChvDBName INPUT - 処理対象DB名 TCHAR szOwnerName[BUF_SIZE]; // 03:@ChvOwnerName INPUT - 処理対象DB名を所有するオーナ名(dbo) TCHAR szTableName[BUF_SIZE]; // 04:@ChvTableName INPUT - 処理対象テーブル名 TCHAR szID[BUF_SIZE]; // 05:@ChvID INPUT - 処理対象サーバのログインID(文字列(sa)) TCHAR szPW[BUF_SIZE]; // 06:@ChvPW INPUT - 処理対象サーバのパスワード TCHAR szInsertFileName[BUF_SIZE]; // 07:@ChvInsertFileName INPUT - 処理対象ファイルのフルパス TCHAR szInsertDate[BUF_SIZE]; // 08:@DtmInsertDate INPUT - 処理対象日 INT nInsertDate; // 1900-01-01を0として1日ごとに1ずつ増える形式で値を取得する INT nSkipFirstRowFlg; // 09:@IntSkipFirstRowFlg INPUT - 処理対象ファイルの最初の行をスキップするかしないか(1:スキップする 0:スキップしない) TCHAR szSkipFirstLetter[BUF_SIZE]; // 10:@ChSkipFirstLetter INPUT - 処理対象ファイルの1行目1文字目にこの引数でもらう文字があれば処理しない(#行は処理しない。) TCHAR szLogFilePath[BUF_SIZE]; // 11:@ChvLogFilePath INPUT - このプロシージャが出すログファイル先パス(\で終わること。このプロシージャでは特にチェックしない。) TCHAR szErrorMessage[BUF_SIZE]; // 12:@ChvErrorMessage OUTPUT - このプロシージャが出すエラーメッセージ INT nDebug; // 13:@IntDebug INPUT - デバッグモード // ↓SPのパラメータを受取る際に必要な変数 BYTE bType[nNum+1]; // ストアドプロシージャのパラメータの型 LONG cbMaxLen[nNum+1]; // ストアドプロシージャのパラメータの最大サイズ LONG cbActualLen[nNum+1]; // ストアドプロシージャのパラメータの長さの実際値へのポインタです。 // 値が 0 (*pcbActualLen == 0 ) のときに *pfNull が FALSE に設定されている場合は、長さ 0 のデータを示します。 BOOL fNull[nNum]; // ストアドプロシージャのパラメータ データのバッファへのポインタです。 // pbData が NULL でない場合、Open Data Services は *pbData に *pcbActualLen バイトのデータを書き込みます。 // pbData が NULL の場合は、*pbData にデータは書き込まれません。 // *pbType、*pcbMaxLen、*pcbActualLen、および *pfNull が関数によって返されます。 // このバッファのメモリは、Open Data Services アプリケーションで管理する必要があります。 //////////////////////////////////////////////////////////////////////////////////////////// // 変数初期化 - なんかこれ呼ぶと一回目変数にゴミがはいっちゃう。。。 //cProcFuncs.InitParameters( szServerName, szDBName, szOwnerName, szTableName, szID, szPW, szInsertFileName, szInsertDate, &nSkipFirstRowFlg, szSkipFirstLetter, szLogFilePath, szErrorMessage, &nDebug ); ZeroMemory( szServerName, sizeof( szServerName ) ); ZeroMemory( szDBName, sizeof( szDBName ) ); ZeroMemory( szOwnerName, sizeof( szOwnerName ) ); ZeroMemory( szTableName, sizeof( szTableName ) ); ZeroMemory( szID, sizeof( szID ) ); ZeroMemory( szPW, sizeof( szPW ) ); ZeroMemory( szInsertFileName, sizeof( szInsertFileName ) ); ZeroMemory( szInsertDate, sizeof( szInsertDate ) ); ZeroMemory( szSkipFirstLetter, sizeof( szSkipFirstLetter ) ); ZeroMemory( szLogFilePath, sizeof( szLogFilePath ) ); ZeroMemory( szErrorMessage, sizeof( szErrorMessage ) ); nSkipFirstRowFlg = 0; nDebug = 0; //////////////////////////////////////////////////////////////////////////////////////////// // メッセージ - Start srv_sendmsg( pSrvProc, SRV_MSG_INFO, 2001, SRV_INFO, 1, NULL, 0, 0, "*** xp_SPEX Start ***", SRV_NULLTERM ); //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータ数チェック if( cProcFuncs.CheckSPNumOfParameters( pSrvProc, nNum ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータ情報を取得 - データタイプ及び長さ情報取得。 // 実際はストアドプロシージャの引数はsrv_paraminfoを用いて取得するが、バッファーオーバーフローの脆弱性を考慮し、 // 後で取得する。 if( cProcFuncs.GetSPParametersInfo( pSrvProc, nNum, bType, cbMaxLen, cbActualLen, fNull ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのOUTPUT型変数の状態を取得 // srv_paramstatus - 特定のリモート ストアド プロシージャ呼び出しパラメータのステータスを返します。 // このパラメータのステータス フラグを持つ int を返します。 // 現在、フラグは 1 つだけあります。ビット 0 が 1 に設定されている場合、パラメータは戻りパラメータです。 // n 番目のパラメータがなかったり、リモート ストアド プロシージャがなかったりする場合は、-1 を返します。 if( cProcFuncs.GetSPParametersStatus( pSrvProc, 12 ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータの型確認 if( cProcFuncs.CheckSPDataType( pSrvProc, nNum, bType ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータのサイズ確認 if( cProcFuncs.CheckSPDataSize( pSrvProc, nNum, cbMaxLen, szServerName, szDBName, szOwnerName, szTableName, szID, szPW, szInsertFileName, szInsertDate, szSkipFirstLetter, szLogFilePath, szErrorMessage ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータ情報を取得 - 値 // 上記までのチェックが済めばローカルバッファに引数コピー if( cProcFuncs.GetSPParametersValue( pSrvProc, nNum, bType, cbMaxLen, cbActualLen, fNull, szServerName, szDBName, szOwnerName, szTableName, szID, szPW, szInsertFileName, szInsertDate, &nInsertDate, &nSkipFirstRowFlg, szSkipFirstLetter, szLogFilePath, szErrorMessage, &nDebug ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータ出力先カラム設定 if( cProcFuncs.SetSPParametersOutputColumn( pSrvProc, nNum, bType, cbMaxLen, cbActualLen, fNull ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータ出力先カラム長設定 // srv_setcollen - 可変長列または NULL 値を許容する列の、現在のデータ長をバイト数で示します。 if( cProcFuncs.SetSPParametersOutputColumnLength( pSrvProc, nNum ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // ストアドプロシージャのパラメータ出力先カラムへデータ設定 if( cProcFuncs.SetSPParametersOutputColumnData( pSrvProc, nNum, szServerName, szDBName, szOwnerName, szTableName, szID, szPW, szInsertFileName, szInsertDate, &nSkipFirstRowFlg, szSkipFirstLetter, szLogFilePath, szErrorMessage, &nDebug ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // クライアントに1行データ送信 if( cProcFuncs.SendRow( pSrvProc ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // クライアントに結果完了メッセージ送信 if( cProcFuncs.SendDone( pSrvProc ) == FALSE ){ return (XP_ERROR); } //////////////////////////////////////////////////////////////////////////////////////////// // メッセージ - 終了 srv_sendmsg( pSrvProc, SRV_MSG_INFO, 2001, SRV_INFO, 1, NULL, 0, 0, "*** xp_SPEX End ***", SRV_NULLTERM ); //////////////////////////////////////////////////////////////////////////////////////////// // ADOを用いてデータをテーブルに挿入 //////////////////////////////////////////////////////////////////////////////////////////// // 構造体設定 InsertInfo.pSrvProc = pSrvProc; lstrcpyn( InsertInfo.szServerName, szServerName, BUF_SIZE ); lstrcpyn( InsertInfo.szDBName, szDBName, BUF_SIZE ); lstrcpyn( InsertInfo.szOwnerName, szOwnerName, BUF_SIZE ); lstrcpyn( InsertInfo.szTableName, szTableName, BUF_SIZE ); lstrcpyn( InsertInfo.szID, szID, BUF_SIZE ); lstrcpyn( InsertInfo.szPW, szPW, BUF_SIZE ); lstrcpyn( InsertInfo.szInsertFileName, szInsertFileName, BUF_SIZE ); lstrcpyn( InsertInfo.szInsertDate, szInsertDate, BUF_SIZE ); InsertInfo.nSkipFirstRowFlg = nSkipFirstRowFlg; lstrcpyn( InsertInfo.szSkipFirstLetter, szSkipFirstLetter, BUF_SIZE ); lstrcpyn( InsertInfo.szLogFilePath, szLogFilePath, BUF_SIZE ); lstrcpyn( InsertInfo.szErrorMessage, szErrorMessage, BUF_SIZE ); InsertInfo.nDebug = nDebug; //////////////////////////////////////////////////////////////////////////////////////////// // ファイルから1行ずつテーブルへインサート - 通常の関数 // スレッドを使うとSPはスレッドが終了するまで待たないのでSPからスレッド呼出し直後にテーブル // のカウントを取られても0件になってしまう現状を回避するため通常の関数を使用。 INT nRet; nRet = InsertThreadMain2( &InsertInfo ); //////////////////////////////////////////////////////////////////////////////////////////// // proc終了 cLog->WriteLogFile( "■■■xp_SPEX終了■■■" ); // XP_NOERRORを返すとストアドプロシージャの戻り値になる if( nRet == XP_ERROR ) return XP_ERROR; return XP_NOERROR ; } //--------------------------------------------------------------------------- // 概要:改行文字位置取得関数 // 機能:改行までの文字数を取得する // 備考: // 戻り値: // 改行位置 // 作成日:2003/11/25 // 更新日: //--------------------------------------------------------------------------- DWORD GL_SearchLineFeedPos(TCHAR *pszInput //入力文字列 ) { DWORD dwLine = 0;//文字数 //入力チェック if(pszInput==NULL){ return dwLine; } while(pszInput[dwLine]!='\0'){ if(pszInput[dwLine]=='\n'){ dwLine++; return(dwLine); } dwLine++; } return(0); } //////////////////////////////////////////////////////////////////////////////////////////// // ローカル関数 //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// // ファイルから1行ずつテーブルへインサート - 通常の関数 INT InsertThreadMain2( STRUCT_INSERTINFO* pInsertInfo ){ //////////////////////////////////////////////////////////////////////////////////////////// // newした構造体に実態をコピー STRUCT_INSERTINFO* lpInsertInfo = new STRUCT_INSERTINFO; lpInsertInfo->pSrvProc = pInsertInfo->pSrvProc; lstrcpyn( lpInsertInfo->szServerName, pInsertInfo->szServerName, BUF_SIZE ); lstrcpyn( lpInsertInfo->szDBName, pInsertInfo->szDBName, BUF_SIZE ); lstrcpyn( lpInsertInfo->szOwnerName, pInsertInfo->szOwnerName, BUF_SIZE ); lstrcpyn( lpInsertInfo->szTableName, pInsertInfo->szTableName, BUF_SIZE ); lstrcpyn( lpInsertInfo->szID, pInsertInfo->szID, BUF_SIZE ); lstrcpyn( lpInsertInfo->szPW, pInsertInfo->szPW, BUF_SIZE ); lstrcpyn( lpInsertInfo->szInsertFileName, pInsertInfo->szInsertFileName, BUF_SIZE ); lstrcpyn( lpInsertInfo->szInsertDate, pInsertInfo->szInsertDate, BUF_SIZE ); lpInsertInfo->nSkipFirstRowFlg = pInsertInfo->nSkipFirstRowFlg; lstrcpyn( lpInsertInfo->szSkipFirstLetter, pInsertInfo->szSkipFirstLetter, BUF_SIZE ); lstrcpyn( lpInsertInfo->szLogFilePath, pInsertInfo->szLogFilePath, BUF_SIZE ); lstrcpyn( lpInsertInfo->szErrorMessage, pInsertInfo->szErrorMessage, BUF_SIZE ); lpInsertInfo->nDebug = pInsertInfo->nDebug; //////////////////////////////////////////////////////////////////////////////////////////// // クラス CReadFileLine cReadFile; // ファイルから1行読込み //////////////////////////////////////////////////////////////////////////////////////////// // 変数 // コネクションオブジェクト、レコードセットオブジェクト _ConnectionPtr pConnection = NULL; // コネクションオブジェクト HANDLE hFile; // ファイルハンドル TCHAR szTmp[BUF_SIZE*2]; // 汎用バッファ INT nError; nError = 0; // catch時に-1になる。 //////////////////////////////////////////////////////////////////////////////////////////// // COM初期化 if( cProcFuncs.CoInitialize( lpInsertInfo->pSrvProc ) == FALSE ){ lstrcpyn( szTmp, "CoInitialize failed...", BUF_SIZE ); cLog->WriteLogFile( szTmp ); return XP_ERROR; } try{ //////////////////////////////////////////////////////////////////////////////////////////// // SQLサーバ接続 if( cProcFuncs.ConnetSQLServer( lpInsertInfo->pSrvProc, pConnection, lpInsertInfo->szServerName, lpInsertInfo->szID, lpInsertInfo->szPW ) == FALSE ){ // ログ lstrcpyn( szTmp, "ConnetSQLServer failed...", BUF_SIZE ); cLog->WriteLogFile( szTmp ); // COMのUnInitialize cProcFuncs.CoUninitialize(); return XP_ERROR; } //////////////////////////////////////////////////////////////////////////////////////////// // CreateFile hFile = CreateFile( lpInsertInfo->szInsertFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); // エラー処理 if( hFile == INVALID_HANDLE_VALUE ) { // ログ wnsprintf( szTmp, BUF_SIZE, "CreateFile failed... return values was INVALID_HANDLE_VALUE, InsertFileName =%s", lpInsertInfo->szInsertFileName ); cLog->WriteLogFile( szTmp ); // COMのUnInitialize cProcFuncs.CoUninitialize(); return XP_ERROR; } // エラー処理 if( GetFileSize( hFile, NULL ) == - 1 ) { // ログ lstrcpyn( szTmp, "GetFileSize failed... return value was -1", BUF_SIZE ); cLog->WriteLogFile( szTmp ); // CloseHandle CloseHandle( hFile ); // COMのUnInitialize cProcFuncs.CoUninitialize(); return XP_ERROR; } //////////////////////////////////////////////////////////////////////////////////////////// // インサート DWORD dwCount = 0; // 行数カウント DWORD dwCountIn = 0; // インサート回数 TCHAR szFileBuf[BUF_SIZE*2]; // ファイルから1行読込んだデータ TCHAR szQuery[BUF_SIZE*2]; // クエリ文字列 //kawahara DWORD dwGetSize = 0; //読み込みバイト数 k DWORD dwFileSize = 0; //ファイルサイズ k DWORD dwReadByte = 0; //読み込みサイズ k DWORD dwDataSize = 0; //データ長 k DWORD dwTempSize = 0; //一時領域文字数 k DWORD dwLineSize = 0; //1行文字数 k DWORD dwStrSize = 0; //処理済文字数 k DWORD dwLineFeedPos = 0; //改行までの文字数 k BOOL bSuccess = TRUE; //作業用 k INT nLine = 0; //行番号 k INT nkLen = 0; static TCHAR m_pszBuf[1000001]; static TCHAR m_pszTempBuf[1000001]; static TCHAR m_pszLineBuf[1000001]; ZeroMemory(m_pszBuf, 1000001); ZeroMemory(m_pszTempBuf, 1000001); ZeroMemory(m_pszLineBuf, 1000001); dwFileSize = dwReadByte = dwDataSize = dwTempSize = dwLineSize = dwStrSize = dwLineFeedPos = 0; nLine = 0; //ファイルサイズ取得 dwFileSize = GetFileSize(hFile , NULL); //読み込みバッファサイズ決定 if(1000000 > dwFileSize){ dwGetSize = dwFileSize; }else{ dwGetSize = 1000000; } dwDataSize = 0; //読み込み処理 while(dwFileSize != dwDataSize){ if(!ReadFile(hFile, (LPVOID)m_pszBuf, dwGetSize, &dwReadByte, NULL)) { bSuccess = FALSE; } m_pszBuf[dwReadByte] = '\0'; dwDataSize = dwDataSize + dwReadByte; dwStrSize = 0; //処理中の文字サイズ初期化 dwLineSize = 0; //loop 読み込んだバイトをすべて処理する while(dwStrSize != dwReadByte){ //1行データを生成する // 余りデータがあった場合は、データを1行データにコピーする // 1行データの文字長を変更する if(dwTempSize != 0){ CopyMemory(m_pszLineBuf + dwLineSize, m_pszTempBuf, dwTempSize); dwLineSize = dwLineSize + dwTempSize; m_pszLineBuf[dwLineSize] = '\0'; dwTempSize=0;//一時領域クリア } //改行位置を検索する // 戻り値 改行あり・なし // なしの場合、データが最後まで読まれていないか確認する。 // 最後まで読み込んでいる場合は、それまでの文字列を1行とする // 読み込んでいない場合は、データを余りデータとして保持して次の行を読み込む // dwLineFeedPos = 0; dwLineFeedPos = GL_SearchLineFeedPos(m_pszBuf + dwStrSize); if(dwLineFeedPos == 0){ if(dwFileSize == dwDataSize){ //1行データにコピーする CopyMemory(m_pszLineBuf + dwLineSize, m_pszBuf + dwStrSize, dwReadByte - dwStrSize); dwLineSize = dwReadByte - dwStrSize + dwLineSize; dwStrSize = dwReadByte; m_pszLineBuf[dwLineSize] = '\0'; }else{ //一時領域にデータコピー CopyMemory(m_pszTempBuf, m_pszBuf + dwStrSize, dwReadByte - dwStrSize); dwTempSize = dwReadByte - dwStrSize; m_pszTempBuf[dwTempSize] = '\0'; //次行読み込みバイト数の設定 if(dwGetSize > (dwFileSize - dwDataSize)){ dwGetSize = dwFileSize - dwDataSize; } //1行読み込み次検索 if(!ReadFile(hFile, (LPVOID)m_pszBuf, dwGetSize, &dwReadByte, NULL)) { bSuccess = FALSE; } dwStrSize = 0; dwDataSize = dwDataSize + dwReadByte; m_pszBuf[dwReadByte] = '\0'; continue; } }else{ //1行データにコピーする CopyMemory(m_pszLineBuf + dwLineSize, m_pszBuf + dwStrSize, dwLineFeedPos); dwLineSize = dwLineFeedPos + dwLineSize; dwStrSize = dwStrSize + dwLineFeedPos; m_pszLineBuf[dwLineSize] = '\0'; } //ルール生成処理 nLine++; lstrcpy(szFileBuf,m_pszLineBuf); nkLen =lstrlen(szFileBuf); /*改行コードを削除する*/ if((nkLen > 2) && (szFileBuf[nkLen-2] == '\r') && (szFileBuf[nkLen-1] == '\n')){ szFileBuf[nkLen - 2] = '\0'; }else if(szFileBuf[nkLen-1]=='\n'){ szFileBuf[nkLen-1]='\0'; } //1行開始位置初期化 dwLineSize=0; //次行読み込みバイト数の設定 if(dwGetSize > (dwFileSize - dwDataSize)){ dwGetSize = dwFileSize - dwDataSize; } ///////////////////////////////////////////////1行の処理を行う///////////////////////////// // 行数カウント dwCount++; // 1行目スキップするか判定 if( lpInsertInfo->nSkipFirstRowFlg == 1 && dwCount == 1 ){ wnsprintf( szTmp, BUF_SIZE*2, "%04d行目:@IntSkipFirstRowFlg=1のためスキップしました。", dwCount ); cLog->WriteLogFile( szTmp ); continue; } // ファイルから取得した1行ラインの初めの文字が特定文字だった場合はスキップ if( szFileBuf[0] == lpInsertInfo->szSkipFirstLetter[0] ){ wnsprintf( szTmp, BUF_SIZE*2, "%04d行目:@ChSkipFirstLetter=%sと一致したためスキップしました。", dwCount, lpInsertInfo->szSkipFirstLetter ); cLog->WriteLogFile( szTmp ); continue; } // SQL文作成 - 引数のDB名からユーザ定義のテーブル名取得 // 初めの1回だけSET ANSI_DEFAULTS OFF をつける。 // SET ANSI_DEFAULTS OFF : INSERT時に文字列が""で囲まれていてもインサートできる。 // 通常のINSERT文↓ // wnsprintf( szQuery, MAX_PATH, "INSERT INTO %s.%s.%s VALUES( 'D', '00000007', '0000000007', 'M', 1978, 7, 7, 7, 'V', '7', 'Reserve', '2000/06/27', '2000/06/27' )", lpInsertInfo->szDBName, lpInsertInfo->szOwnerName, lpInsertInfo->szTableName ); // 文字列が""で囲まれたINSERT文↓ // wnsprintf( szQuery, MAX_PATH, "SET ANSI_DEFAULTS OFF INSERT INTO %s.%s.%s VALUES( \"AD", \"00000008\", \"0000000008\", \"M\", 1978, 7, 7, 7, \"V\", \"7\", \"Reserve\", \"2000/06/27\", \"2000/06/27\" )", lpInsertInfo->szDBName, lpInsertInfo->szOwnerName, lpInsertInfo->szTableName ); if( dwCountIn == 0 ){ // @DtmInsertDateが空かNULLの場合は、ファイルから読取った1行をそのままインサート if( lstrcmpi( lpInsertInfo->szInsertDate, "" ) == 0 || lpInsertInfo->szInsertDate == NULL ){ wnsprintf( szQuery, BUF_SIZE*2, "SET ANSI_DEFAULTS OFF INSERT INTO %s.%s.%s VALUES( %s )", lpInsertInfo->szDBName, lpInsertInfo->szOwnerName, lpInsertInfo->szTableName, szFileBuf ); } // @DtmInsertDateが空かNULLの以外場合は、ファイルから読取った1行に@DtmInsertDateを足してインサート else{ wnsprintf( szQuery, BUF_SIZE*2, "SET ANSI_DEFAULTS OFF INSERT INTO %s.%s.%s VALUES( %s,\"%s\" )", lpInsertInfo->szDBName, lpInsertInfo->szOwnerName, lpInsertInfo->szTableName, szFileBuf, lpInsertInfo->szInsertDate ); } } else{ if( lstrcmpi( lpInsertInfo->szInsertDate, "" ) == 0 || lpInsertInfo->szInsertDate == NULL ){ wnsprintf( szQuery, BUF_SIZE*2, "INSERT INTO %s.%s.%s VALUES( %s )", lpInsertInfo->szDBName, lpInsertInfo->szOwnerName, lpInsertInfo->szTableName, szFileBuf ); } else{ wnsprintf( szQuery, BUF_SIZE*2, "INSERT INTO %s.%s.%s VALUES( %s,\"%s\" )", lpInsertInfo->szDBName, lpInsertInfo->szOwnerName, lpInsertInfo->szTableName, szFileBuf, lpInsertInfo->szInsertDate ); } } // ログ - インサートする文字列 wnsprintf( szTmp, BUF_SIZE, "%04d行目:%s", dwCount, szQuery ); cLog->WriteLogFile( szTmp ); // SQL文を_bstr_型変換 _bstr_t bstrQuery( szQuery ); // SQL文実行 - インサート _variant_t vRecsAffected(0L); pConnection->Execute( bstrQuery, &vRecsAffected, adOptionUnspecified ); // インサート回数カウント dwCountIn++; /////////////////////////////////////////////////////////////////////////////////////////////// } } } catch( _com_error &e ){ // ログ lstrcpyn( szTmp, "_com_error", BUF_SIZE ); cLog->WriteLogFile( szTmp ); // エラーの特定 ADOPrintProviderError(pConnection); ADOPrintComError(e); // フラグ設定 nError = XP_ERROR; } //////////////////////////////////////////////////////////////////////////////////////////// // CloseHandle CloseHandle( hFile ); //////////////////////////////////////////////////////////////////////////////////////////// // コネクション破棄 if( pConnection ){ pConnection->Close(); pConnec |