001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.process; 017 018import java.sql.Connection; 019import java.sql.Statement; 020import java.sql.ResultSet; 021import java.sql.SQLException; 022import java.util.Set ; 023import java.util.HashSet ; 024import java.util.Map ; 025import java.util.LinkedHashMap ; 026 027import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 028import org.opengion.fukurou.system.LogWriter; 029import org.opengion.fukurou.util.Argument; 030import org.opengion.fukurou.util.SystemParameter; 031import org.opengion.fukurou.util.HybsEntry ; 032import org.opengion.fukurou.db.ConnectionFactory; 033 034/** 035 * Process_BulkQueryは、データベースから読み取った内容を、一括処理する、 036 * FirstProcess と、ChainProcess のインターフェースを両方持った、実装クラスです。 037 * ParamProcess のサブクラス(Process_DBParam)にセットしたり、加工したりします。 038 * 039 * このクラスは、上流から、下流への処理は、1度しか実行されません。 040 * FirstProcess の検索結果は、Set オブジェクトとして、Process_DBParam に渡します。 041 * ChainProcess は、その結果を取り出し、自分自身の処理結果と合せて加工します。 042 * 043 * FirstProcess では、-action は、query のみです。 044 * query は、指定のSQL文を実行し、結果のSetをParamProcessに設定します。 045 * ChainProcess では、-action は、query、bulkSet、minus、intersect が指定できます。 046 * query は、上記と同じです。 047 * minus は、先のSetから、SQL文の実行結果を引き算し、結果Setを再設定します。 048 * intersect は、先のSetから、SQL文の実行結果と重複する結果Setを再設定します。 049 * bulkSet は、先のSetを取り出し、SQL文に加味して処理します。 050 * 流れ的には、query で検索し、minusまたはintersect でSetオブジェクトを加工し、bulkSet で 051 * 利用します。例えば、ORACLEから、ユニークキーのSetを作成し、SQLServerのユニークキーを 052 * minusした結果を、ORACLEからDELETEすれば、不要なデータを削除するなどの処理が実行可能になります。 053 * また、単純に、query だけを、チェインすれば、単発のUPDATE文を実行することが可能です。 054 * 055 * データベース接続先等は、ParamProcess のサブクラス(Process_DBParam)に 056 * 設定された接続(Connection)を使用します。 057 * DBID は、Process_DBParam の -configFile で指定する DBConfig.xml ファイルを使用します。 058 * 059 * 引数文字列中にスペースを含む場合は、ダブルコーテーション("") で括って下さい。 060 * 引数文字列の 『=』 の前後には、スペースは挟めません。必ず、-key=value の様に 061 * 繋げてください。 062 * 063 * SQL文には、{@DATE.YMDH}等のシステム変数が使用できます。 064 * 065 * @og.formSample 066 * Process_BulkQuery -action=query -dbid=DBGE -sql="select KEY from TABLE_X" 067 * 068 * -action=処理方法(必須) : 実行する処理方法を指定します 069 * -action=query 単なるSQL文を実行します。 070 * -action=bulkSet 実行したSQL文の結果を、Set<String> オブジェクトに設定します。 071 * -action=minus Set<String> オブジェクトと、ここでの実行結果の差分をとります。 072 * -action=plus Set<String> オブジェクトと、ここでの実行結果の加算をします。 073 * -action=intersect Set<String> オブジェクトと、ここでの実行結果の積分をとります。 074 * [ -dbid=DB接続ID ] : -dbid=DBGE (例: Process_DBParam の -configFile で指定する DBConfig.xml ファイルで規定) 075 * [ -sql=検索SQL文 ] : -sql="select * from GEA08" 076 * [ -sqlFile=検索SQLファイル ] : -sqlFile=select.sql 077 * -sql= を指定しない場合は、ファイルで必ず指定してください。 078 * [ -sql_XXXX=固定値 ] : -sql_SYSTEM_ID=GE 079 * SQL文中の{@XXXX}文字列を指定の固定値で置き換えます。 080 * WHERE SYSTEM_ID='{@SYSTEM_ID}' ⇒ WHERE SYSTEM_ID='GE' 081 * [ -bulkKey=XXXX ] : -bulkKey=XXXX 082 * SQL文中の{@XXXX}文字列をProcess_BulkQuery等で取得した値で置き換えます。 083 * WHERE SYSTEM_ID IN ( {@XXXX} ) ⇒ WHERE SYSTEM_ID IN ( 'AA','BB','CC' ) 084 * [ -bulkType=NUM|STR ] : -bulkType=STR 085 * Bulkの値を文字列に変換する場合に、数字型か、文字型を指定します。 086 * 数字型では、AA,BB,CC とし、文字型では、'AA','BB','CC' に変換します(初期値:STR)。 087 * [ -fetchSize=1000 ] :フェッチする行数(初期値:1000) 088 * [ -display=[false/true] ] :結果を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない]) 089 * [ -debug=[false/true] ] :デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない]) 090 * 091 * @og.rev 5.3.4.0 (2011/04/01) 新規追加 092 * @version 4.0 093 * @author Kazuhiko Hasegawa 094 * @since JDK5.0, 095 */ 096public class Process_BulkQuery extends AbstractProcess implements FirstProcess , ChainProcess { 097 private static final int MAX_BULK_SET = 500 ; // ORACLE の制約が 1000 なので。 098 099 private static final String ACT_QUERY = "query" ; 100 private static final String ACT_BULKSET = "bulkSet" ; 101 private static final String ACT_MINUS = "minus" ; 102 private static final String ACT_PLUS = "plus" ; // 6.3.1.1 (2015/07/10) 追加 103 private static final String ACT_INTERSECT = "intersect" ; 104 105 private static final String[] ACTION_LST = { ACT_QUERY,ACT_BULKSET,ACT_MINUS,ACT_PLUS,ACT_INTERSECT }; 106 107// /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ {@value} */ 108// private static final int DB_FETCH_SIZE = 1001 ; 109 110 private String actionCmd ; // SQL結果を加工(query:実行、minus:引き算、intersect:重複分) 111 private String dbid ; // メインDB接続ID 112 113// private String bulkKey ; // 8.5.4.2 (2024/01/12) PMD 7.0.0 SingularField 114 private boolean bulkType = true; // true:STR , false:NUM 115 116 private int sqlCount ; // SQL文の処理件数 117 private int setCount ; // 取り出したSetの件数 118 private int outCount ; // マージ後のSetの件数 119 120 private int fetchSize = 1000; 121 private boolean display ; // 表示しない 122 private boolean debug ; // デバッグ情報 123 private boolean firstTime = true; // 最初の一回目 124 125 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 126 private static final Map<String,String> MUST_PROPARTY ; // [プロパティ]必須チェック用 Map 127 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 128 private static final Map<String,String> USABLE_PROPARTY ; // [プロパティ]整合性チェック Map 129 130 static { 131 MUST_PROPARTY = new LinkedHashMap<>(); 132 MUST_PROPARTY.put( "action", "実行する処理方法を指定します。(query|minus|plus|intersect)" ); 133 134 USABLE_PROPARTY = new LinkedHashMap<>(); 135 USABLE_PROPARTY.put( "dbid", "Process_DBParam の -configFile で指定する DBConfig.xml ファイルで規定" ); 136 USABLE_PROPARTY.put( "sql", "検索SQL文(sql or sqlFile 必須)例: \"select * from GEA08\"" ); 137 USABLE_PROPARTY.put( "sqlFile", "検索SQLファイル(sql or sqlFile 必須)例: select.sql" ); 138 USABLE_PROPARTY.put( "sql_", "SQL文中の{@XXXX}文字列を指定の固定値で置き換えます。" + 139 CR + "WHERE SYSTEM_ID='{@SYSTEM_ID}' ⇒ WHERE SYSTEM_ID='GE'" ); 140 USABLE_PROPARTY.put( "dbid2", "DB接続ID2 例: Process_DBParam の -configFile で指定する DBConfig.xml ファイルで規定" ); 141 USABLE_PROPARTY.put( "sql2", "検索SQL文2(sql or sqlFile 必須)例: \"select * from GEA08\"" ); 142 USABLE_PROPARTY.put( "sqlFile2", "検索SQLファイル2(sql or sqlFile 必須)例: select.sql" ); 143 USABLE_PROPARTY.put( "sql2_", "SQL文2中の{@XXXX}文字列を指定の固定値で置き換えます。" + 144 CR + "WHERE SYSTEM_ID='{@SYSTEM_ID}' ⇒ WHERE SYSTEM_ID='GE'" ); 145 USABLE_PROPARTY.put( "bulkKey", "SQL文中の{@XXXX}文字列をProcess_BulkQuery等で取得した値で置き換えます。" + 146 CR + "WHERE SYSTEM_ID IN ( {@XXXX} ) ⇒ WHERE SYSTEM_ID IN ( 'AA','BB','CC' )" ); 147 USABLE_PROPARTY.put( "bulkType", "Bulkの値を文字列に変換する場合に、文字型か、数字型を指定します。" + 148 CR + "数字型では、AA,BB,CC とし、文字型では、'AA','BB','CC' に変換します。(初期値:STR)" ); 149 USABLE_PROPARTY.put( "fetchSize","フェッチする行数 (初期値:1000)" ); 150 USABLE_PROPARTY.put( "display", "結果を標準出力に表示する(true)かしない(false)か" + 151 CR + "(初期値:false:表示しない)" ); 152 USABLE_PROPARTY.put( "debug", "デバッグ情報を標準出力に表示する(true)かしない(false)か" + 153 CR + "(初期値:false:表示しない)" ); 154 } 155 156 /** 157 * デフォルトコンストラクター。 158 * このクラスは、動的作成されます。デフォルトコンストラクターで、 159 * super クラスに対して、必要な初期化を行っておきます。 160 * 161 */ 162 public Process_BulkQuery() { 163 super( "org.opengion.fukurou.process.Process_BulkQuery",MUST_PROPARTY,USABLE_PROPARTY ); 164 } 165 166 /** 167 * プロセスの初期化を行います。初めに一度だけ、呼び出されます。 168 * 初期処理(ファイルオープン、DBオープン等)に使用します。 169 * 170 * @og.rev 5.3.9.0 (2011/09/01) 1000件を超えた場合の処理を追加 171 * @og.rev 6.3.1.1 (2015/07/10) plus アクションの追加 172 * @og.rev 8.5.4.2 (2024/01/12) PMD 7.0.0 SingularField 対応 173 * 174 * @param paramProcess データベースの接続先情報などを持っているオブジェクト 175 */ 176 public void init( final ParamProcess paramProcess ) { 177 final Argument arg = getArgument(); 178 179 actionCmd = arg.getProparty( "action" , null , ACTION_LST ); 180 181 fetchSize = arg.getProparty( "fetchSize" , fetchSize ); 182 display = arg.getProparty( "display" , display ); 183 debug = arg.getProparty( "debug" , debug ); 184 185 dbid = arg.getProparty( "dbid"); 186 String sql = arg.getFileProparty( "sql" , "sqlFile",true ); 187 if( debug ) { println( "入力SQL:" + sql ); } 188 189 final HybsEntry[] entry =arg.getEntrys( "sql_" ); //配列 190 final SystemParameter sysParam = new SystemParameter( sql ); 191 sql = sysParam.replace( entry ); 192 if( debug ) { println( "変換SQL:" + sql ); } 193 194 if( ACT_BULKSET.equalsIgnoreCase( actionCmd ) ) { 195// bulkKey = arg.getProparty( "bulkKey" ); 196 final String bulkKey = arg.getProparty( "bulkKey" ); // 8.5.4.2 (2024/01/12) PMD 7.0.0 SingularField 197 final String bkType = arg.getProparty( "bulkType" ); 198 if( bkType != null ) { bulkType = "STR".equalsIgnoreCase( bkType ); } // 初期値が true なので、null チャックは外せません。 199 200 final Set<String> setData = paramProcess.getBulkData(); 201 if( debug ) { println( setData.toString() ); } 202 setCount = setData.size(); 203 204 if( setCount > 0 ) { 205 // 5.3.9.0 (2011/09/01) 1000件を超えた場合の処理を追加 206 // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach 207// final String[] sqls = makeBulkQuery( sql,bulkKey,bulkType,setData ); 208// for( int i=0; i<sqls.length; i++ ) { 209// if( debug ) { println( "BulkSQL:" + sqls[i] ); } 210// createSetData( paramProcess, dbid, sqls[i] ); 211// } 212 for( final String blksql : makeBulkQuery( sql,bulkKey,bulkType,setData ) ) { 213 if( debug ) { println( "BulkSQL:" + blksql ); } 214 createSetData( paramProcess, dbid, blksql ); 215 } 216 } 217 } 218 else if( ACT_QUERY.equalsIgnoreCase( actionCmd ) ) { 219 final Set<String> setData2 = createSetData( paramProcess, dbid, sql ); 220 if( debug ) { println( setData2.toString() ); } 221 setCount = setData2.size(); 222 outCount = setCount; 223 paramProcess.setBulkData( setData2 ); 224 } 225 else { 226 final Set<String> setData = paramProcess.getBulkData(); 227 final Set<String> setData2 = createSetData( paramProcess, dbid, sql ); 228 setCount = setData2.size(); 229 230 if( ACT_MINUS.equalsIgnoreCase( actionCmd ) ) { 231 setData.removeAll( setData2 ); 232 } 233 else if( ACT_PLUS.equalsIgnoreCase( actionCmd ) ) { // 6.3.1.1 (2015/07/10) 234 setData.addAll( setData2 ); 235 } 236 else if( ACT_INTERSECT.equalsIgnoreCase( actionCmd ) ) { 237 setData.retainAll( setData2 ); 238 } 239 outCount = setData.size(); 240 if( debug ) { println( setData.toString() ); } 241 paramProcess.setBulkData( setData ); 242 } 243 } 244 245 /** 246 * プロセスの終了を行います。最後に一度だけ、呼び出されます。 247 * 終了処理(ファイルクローズ、DBクローズ等)に使用します。 248 * 249 * @param isOK トータルで、OKだったかどうか [true:成功/false:失敗] 250 */ 251 public void end( final boolean isOK ) { 252 // 何もありません。 253 } 254 255 /** 256 * このデータの処理において、次の処理が出来るかどうかを問い合わせます。 257 * この呼び出し1回毎に、次のデータを取得する準備を行います。 258 * 259 * @return 処理できる:true / 処理できない:false 260 */ 261 @Override // FirstProcess 262 public boolean next() { 263 return firstTime; 264 } 265 266 /** 267 * 引数の LineModel を処理するメソッドです。 268 * 変換処理後の LineModel を返します。 269 * 後続処理を行わない場合(データのフィルタリングを行う場合)は、 270 * null データを返します。つまり、null データは、後続処理を行わない 271 * フラグの代わりにも使用しています。 272 * なお、変換処理後の LineModel と、オリジナルの LineModel が、 273 * 同一か、コピー(クローン)かは、各処理メソッド内で決めています。 274 * ドキュメントに明記されていない場合は、副作用が問題になる場合は、 275 * 各処理ごとに自分でコピー(クローン)して下さい。 276 * 277 * @param data オリジナルのLineModel 278 * 279 * @return 処理変換後のLineModel 280 */ 281// @SuppressWarnings(value={"unchecked"}) 282 @Override // ChainProcess 283 public LineModel action( final LineModel data ) { 284 return data ; 285 } 286 287 /** 288 * 最初に、行データである LineModel を作成します 289 * FirstProcess は、次々と処理をチェインしていく最初の行データを 290 * 作成して、後続の ChainProcess クラスに処理データを渡します。 291 * 292 * @param rowNo 処理中の行番号 293 * 294 * @return 処理変換後のLineModel 295 */ 296 @Override // FirstProcess 297 public LineModel makeLineModel( final int rowNo ) { 298 firstTime = false; // 一度しか処理しないため、false を設定する。 299 300 final LineModel model = new LineModel(); 301 302 model.setRowNo( rowNo ); 303 304 return model; 305 } 306 307 /** 308 * 内部で使用する Set オブジェクトを作成します。 309 * Exception 以外では、必ず Set<String> オブジェクトを返します。 310 * 311 * @og.rev 5.3.9.0 (2011/09/01) 1000件を超えた場合の処理を追加 312 * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。 313 * 314 * @param paramProcess データベースの接続先情報などを持っているオブジェクト 315 * @param dbid 接続先ID 316 * @param sql 実行するSQL文(検索系) 317 * 318 * @return 実行結果から取り出した、最初のカラムのみを集めた Setオブジェクト 319 * @throws RuntimeException データベース処理ができなかった場合。 320 */ 321 private Set<String> createSetData( final ParamProcess paramProcess, final String dbid, final String sql ) { 322 final Set<String> data = new HashSet<>(); 323 324 Connection connection = null; 325 326 try { 327 connection = paramProcess.getConnection( dbid ); 328 // 6.4.2.1 (2016/02/05) try-with-resources 文 329 try( Statement stmt = connection.createStatement() ) { 330 if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); } 331 if( stmt.execute( sql ) ) { // true:検索系 , false:更新系 332 try( ResultSet resultSet = stmt.getResultSet() ) { 333 while( resultSet.next() ) { 334 sqlCount++ ; 335 final String str = resultSet.getString(1); 336 if( display ) { println( str ); } 337 data.add( str ); 338 } 339 } 340 } 341 else { 342 sqlCount += stmt.getUpdateCount(); 343 } 344 } 345 } 346 catch( final SQLException ex) { 347 final String errMsg = "SQL を実行できませんでした。" + CR 348 + "errMsg=[" + ex.getMessage() + "]" + CR 349 + "errorCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR 350 + "DBID=" + dbid + CR 351 + "SQL =" + sql ; 352 353 throw new OgRuntimeException( errMsg,ex ); 354 } 355 finally { 356 357 ConnectionFactory.remove( connection,dbid ); 358 } 359 return data; 360 } 361 362 /** 363 * 内部で使用する Set オブジェクトを作成します。 364 * Exception 以外では、必ず Set<String[]> オブジェクトを返します。 365 * 366 * @og.rev 5.3.9.0 (2011/09/01) 1000件を超えた場合の処理を追加 367 * 368 * @param sql オリジナルのSQL文 369 * @param bulkKey 一括処理で置き換えるキー文字列 370 * @param bulkType 文字型(true)か、数字型(false)を指定 371 * @param setData 一括処理の元となるSetオブジェクト 372 * 373 * @return オリジナルのSQL文 に 一括処理の文字列と置換したSQL文の配列 374 */ 375 private String[] makeBulkQuery( final String sql, final String bulkKey, final boolean bulkType,final Set<String> setData ) { 376 final String[] sqls = new String[ setData.size()/MAX_BULK_SET + 1 ]; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal 377 int idx = 0; 378 int cnt = 0; 379 380 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 381 String bulkVal = null; 382 if( bulkType ) { // 文字列の場合 383 for( final String key : setData ) { 384 cnt++; 385 buf.append( ",'" ).append( key ).append( '\'' ); 386 if( cnt >= MAX_BULK_SET ) { 387 bulkVal = buf.substring( 1 ); // 先頭のコロンをはずす 388 sqls[idx++] = sql.replace( "{@" + bulkKey + "}" ,bulkVal ); 389 cnt = 0; 390 buf.setLength(0); // 6.1.0.0 (2014/12/26) refactoring 391 } 392 } 393 if( cnt > 0 ) { // きっちりで終わらない場合 394 bulkVal = buf.substring( 1 ); // 先頭のコロンをはずす 395 sqls[idx] = sql.replace( "{@" + bulkKey + "}" ,bulkVal ); 396 } 397 } 398 else { // 数字の場合 399 for( final String key : setData ) { 400 cnt++; 401 buf.append( ',' ).append( key ); // 6.0.2.5 (2014/10/31) char を append する。 402 if( cnt >= MAX_BULK_SET ) { 403 bulkVal = buf.substring( 1 ); // 先頭のコロンをはずす 404 sqls[idx++] = sql.replace( "{@" + bulkKey + "}" ,bulkVal ); 405 cnt = 0; 406 buf.setLength(0); // 6.1.0.0 (2014/12/26) refactoring 407 } 408 } 409 if( cnt > 0 ) { // きっちりで終わらない場合 410 bulkVal = buf.substring( 1 ); // 先頭のコロンをはずす 411 sqls[idx] = sql.replace( "{@" + bulkKey + "}" ,bulkVal ); 412 } 413 } 414 415 return sqls; 416 } 417 418 /** 419 * プロセスの処理結果のレポート表現を返します。 420 * 処理プログラム名、入力件数、出力件数などの情報です。 421 * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような 422 * 形式で出してください。 423 * 424 * @return 処理結果のレポート 425 */ 426 public String report() { 427 // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX' 428 return "[" + getClass().getName() + "]" + CR 429// final String report = "[" + getClass().getName() + "]" + CR 430 + TAB + "Action : " + actionCmd + CR 431 + TAB + "DBID : " + dbid + CR 432 + TAB + "sqlCount : " + sqlCount + CR 433 + TAB + "setCount : " + setCount + CR 434 + TAB + "outCount : " + outCount ; 435 436// return report ; 437 } 438 439 /** 440 * このクラスの使用方法を返します。 441 * 442 * @return このクラスの使用方法 443 * @og.rtnNotNull 444 */ 445 public String usage() { 446 final StringBuilder buf = new StringBuilder( 1200 ) 447 .append( "Process_BulkQueryは、データベースから読み取った内容を、一括処理するために、" ).append( CR ) 448 .append( "ParamProcess のサブクラス(Process_DBParam)にセットしたり、加工したりする" ).append( CR ) 449 .append( "FirstProcess と、ChainProcess のインターフェースを両方持った、実装クラスです。" ).append( CR ) 450 .append( CR ) 451 .append( "このクラスは、上流から、下流への処理は、1度しか実行されません。" ).append( CR ) 452 .append( "FirstProcess の検索結果は、Set オブジェクトとして、Process_DBParam に渡します。" ).append( CR ) 453 .append( "ChainProcess は、その結果を取り出し、自分自身の処理結果と合せて加工します。" ).append( CR ) 454 .append( CR ) 455 .append( "FirstProcess では、-action は、query のみです。" ).append( CR ) 456 .append( " query は、指定のSQL文を実行し、結果のSetをParamProcessに設定します。" ).append( CR ) 457 .append( "ChainProcess では、-action は、query、bulkSet、minus、intersect が指定できます。" ).append( CR ) 458 .append( " query は、上記と同じです。" ).append( CR ) 459 .append( " minus は、先のSetから、SQL文の実行結果を引き算し、結果Setを再設定します。" ).append( CR ) 460 .append( " intersect は、先のSetから、SQL文の実行結果と重複する結果Setを再設定します。" ).append( CR ) 461 .append( " bulkSet は、先のSetを取り出し、SQL文に加味して処理します。" ).append( CR ) 462 .append( CR ) 463 .append( "流れ的には、query で検索し、minusまたはintersect でSetオブジェクトを加工し、" ).append( CR ) 464 .append( "bulkSet で利用します。例えば、ORACLEから、ユニークキーのSetを作成し、" ).append( CR ) 465 .append( "SQLServerのユニークキーをminusした結果を、ORACLEからDELETEすれば、不要な" ).append( CR ) 466 .append( "データを削除するなどの処理が実行可能になります。また、単純に、query だけを、" ).append( CR ) 467 .append( "チェインすれば、単発のUPDATE文を実行することが可能です。" ).append( CR ) 468 .append( CR ) 469// .append( "データベース接続先等は、ParamProcess のサブクラス(Process_DBParam)に" ).append( CR ) 470// .append( "設定された接続(Connection)を使用します。" ).append( CR ) 471// .append( CR ) 472// .append( "SQL文には、{@DATE.YMDH}等のシステム変数が使用できます。" ).append( CR ) 473 .append( DB_PARAM_USAGE ) // 8.5.6.1 (2024/03/29) 継承元使用 474 .append( CR ) 475// .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。" ).append( CR ) 476// .append( "引数文字列の 『=』 の前後には、空白は挟めません。必ず、-key=value の様に" ).append( CR ) 477// .append( "繋げてください。" ).append( CR ) 478 .append( PROCESS_PARAM_USAGE ) // 8.5.6.1 (2024/03/29) 継承元使用 ※ 場所の移動 479 .append( CR ).append( CR ) 480 .append( getArgument().usage() ).append( CR ); 481 482 return buf.toString(); 483 } 484 485 /** 486 * このクラスは、main メソッドから実行できません。 487 * 488 * @param args コマンド引数配列 489 */ 490 public static void main( final String[] args ) { 491 LogWriter.log( new Process_BulkQuery().usage() ); 492 } 493}