- - PR -
C# foreach文について教えてください
1
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2004-04-01 11:34
こんにちは。ゆきおといいます。
C#でOracleDBから2つのテーブルを比較するアプリケーションを作成しています。 コントロールブレーク処理を行い、2つのテーブルを結合させようと考えています。 【結合条件】 ・マスタとトランザクションをキーで比較し、一致する場合は結合。 ・一致しない場合でもスペースを付与し結合 ※両テーブルはキーの昇順でソート済み 【環境】 OS:Windows2000 SP4 Oracle:Oracle9i Release 9.2.0 トライアル版 言語:Visual C#.NET + Oracle Data Provider for .NET(ODP.NET) .Net Framework v1.0 【C#、ソースコード】 // コントロールブレーク処理をします private void controlBreak(OracleConnection con , DataSet mstDs , DataSet trnDs) { // マスタ側のループです foreach(DataRow mstDr in mstDs.Tables[0].Rows) { // トランザクション側のループです(@) foreach(DataRow trnDr in trnDs.Tables[0].Rows) { // マスタ.ノード名とトランザクション.ノード名を比較します if (String.Compare(mstDr[0].ToString(),trnDr[0].ToString()) == 0) { // 出力テーブルに書き込みます this.insData(con , mstDr , trnDr , 0); break; } // 一致しない場合は文字列の大小比較を行う else if (String.Compare(mstDr[0].ToString(),trnDr[0].ToString()) < 0) { // マスタ側が小さい場合はマスタ行のみの出力となる this.insData(con , mstDr , trnDr , 1); break; } // マスタ側が大きい場合は何もせずにトランザクションをリードする } } } 【問題箇所】 上記コードで処理を行ったところ、プログラムミスが見つかりました。トランザクション側の ループ(@)では常に開始される行が「trnDs.Tables[0].Rows」の1行目から開始されてしまう点です。この部分はあらかじめfor文で2次元配列に格納し、トランザクション側のループ(@)をfor文に置き換えようと考えています。 【質問】 foreachは必ず最初から始まるのでしょうか?(要素の途中から開始できますか)またこういった2つのテーブルを結合するようなときはどのようなコードで結合しているか教えていただけるとありがたいです。 | ||||||||
|
投稿日時: 2004-04-01 14:57
直接の回答ではありませんが。
C#コードでのコントロールブレークではなく、DB上での両テーブルのOUTER JOINではいけませんでしょうか。 一致しない場合はNULLが入りますが、これをスペースに置き換えるのはそう難しくはないと思います。 #もしかして、昔ホスト系の開発をされていた方ですか? #最近ホスト系に首を突っ込んでいるのですが、似たような処理を良く見かけます。 | ||||||||
|
投稿日時: 2004-04-01 15:48
一番良いのはすなめりさんのおっしゃっているOUTER JOIN(外部結合)で表を結合したものを取得する方法です。Oracle9iならできます。
おそらくパフォーマンスが桁違いだと思います。(桁どころか二桁かも) foreach文では必ず最初からだと思います。 どうしてもやるなら、DataRowCollectionクラスはGetEnumerator()メソッドを実装していますので、IEnumeratorオブジェクトを取得できます。 これを使ってコードでMoveNext()しながらDataRowオブジェクトを一行ずつ取得していくという方法になると思います。 もちろんこの方法はお勧めしません。 | ||||||||
|
投稿日時: 2004-04-01 17:21
すめなりさん、一郎さんこんにちは。
ゆきおです。 返信ありがとうございます。今時点ではコードを作成し、 動作させることができましたが...
この方法を取ってしまいました。パフォーマンスが悪そうですね。 現状はともかくとして、大事なのはDB上での両テーブルのOUTER JOINですね。あらかじめ結合してればパフォーマンスも良いということですね。この方法に変えると早そうですね。 (そうすると結合のC#コードが全く意味がなくなってしまい、SQL*Plus上でできてしまいそうな気が・・・)
ホスト系の開発はしたことが無いんですよ。ただホスト系はCOBOL言語が多いような気がします。学生のときですがCOBOL言語を使っていました。そのため古いアルゴリズムの発想が出てしまうような気がします。COBOL、C、VB、ときてC#に手を出しています。C#ももう少し理解を深めようとがんばっています。 お二人ともありがとうございました。テーブルをOUTER JOINで結合するSQL文を考えてみます。 参考までに現在のコードを記します。またコメント等あればよろしくお願いします。 【改定後コード】 private void controlBreak(OracleConnection con , DataSet mstDs , DataSet trnDs) { // トランザクション.テーブル用にインデクサを定義します IEnumerator trnEnum = trnDs.Tables[0].Rows.GetEnumerator(); trnEnum.MoveNext(); int i = 0; int trnCnt = trnDs.Tables[0].Rows.Count; // マスタ側のループです foreach(DataRow mstDr in mstDs.Tables[0].Rows) { // トランザクション側のループです while(i <= trnCnt) { DataRow trnDr = trnEnum.Current as System.Data.DataRow; // マスタ.ノード名とトランザクション.ノード名を比較します if (String.Compare(mstDr[0].ToString(),trnDr[0].ToString()) == 0) { // 出力テーブルに書き込みます this.insData(con , mstDr , trnDr , 0); // トランザクションをリードします trnEnum.MoveNext(); i++; break; } // 一致しない場合は文字列の大小比較を行う else if (String.Compare(mstDr[0].ToString(),trnDr[0].ToString()) < 0) { // マスタ側が小さい場合はマスタ行のみの出力となる this.insData(con , mstDr , trnDr , 1); break; } // マスタ側が大きい場合は何もせずにトランザクションをリードする trnEnum.MoveNext(); i++; } } } |
1