- ベストアンサー
SELECT CASEについての質問です
以前教えていただいたコードがあるのですが どうしても分からない部分があったので質問させていただきます Private Sub Sample77() Dim rs As ADODB.Recordset Dim rsUP As New ADODB.Recordset Dim i As Integer Dim iCount As Long iCount = 0 rsUP.Source = "SELECT * FROM 個人T WHERE 登録番号 LIKE 'ZZZZ%' ORDER BY 登録番号;" rsUP.Open , CurrentProject.Connection, adOpenKeyset, adLockOptimistic Set rs = rsUP.Clone(adLockReadOnly) While (Not rsUP.EOF) iCount = iCount + 1 Debug.Print iCount & " 件目 " & rsUP("登録番号") rs.Filter = "[連番] = 'XXXX" & rsUP("登録番号") & "'" If (Not rs.EOF) Then For i = 0 To rsUP.Fields.Count - 1 Select Case rsUP.Fields(i).Name ☆ Case "登録番号", "連番" ☆ Case Else ☆ rsUP.Fields(i).Value = rs.Fields(i).Value☆ End Select Next rsUP.Update End If rsUP.MoveNext Wend rs.Close rsUP.Close Set rs = Nothing End Sub ☆の部分の動作がどうしてもわかりません。 "登録番号"と"連番"以外のフィールドを別レコードへ移動できるのですが 調べてもCASEの後にはなにか条件に当てはまった場合の処理を書く必要があると思うのですが 今回のコードにはそれが無いように思えます。 ☆の部分の動作を教えていただけないでしょうか よろしくお願いします。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
#3です。 >CASE1つ目に該当するからといってそこでSELECT CASEは終了にはならない これは考え方がおかしいのは。 --ーAーX処理ー| | | ー |--BーY処理ーーー次の処理(ENDSELECTの次) | | --ーCーZ処理ー| のシェーマをコード化するものと思う。 ーーAーーーーーーーB----ーーーCーーーーーーーーー次の処理 | | | | | | --X処理ー| |ーY処理ー| |ーーZ処理ー| ではない。
その他の回答 (6)
- 30246kiku
- ベストアンサー率73% (370/504)
> 記述を短くするだけでやはり気持ち早くなる感じなのですかね。 少なくとも効果はあると思います。(内容によると思いますが) 私は、1度変数に代入して使い回すことをよくします。 実際には、記述を短くする、辿ったところを基準とするための記述として、With があります。 With を使わなくて済むのなら使いたくない。これは私の好き嫌いです。
お礼
ご回答ありがとうございます。 Withステートメントのヘルプをみてみましたが、 私は変数に代入して使う方が理解しやすく感じました。 私も代入してから使いまわすことが多くなりそうです(笑)
- 30246kiku
- ベストアンサー率73% (370/504)
途中から脱線しますので、ポイントは他の方へ 以下、Access2007 VBE のヘルプからの引用になります。(部分的に削除してます) ------ 引用 ここから 構文 Select Case testexpression [Case expressionlist-n [statements-n]] ... [Case Else [elsestatements]] End Select 指定項目 内容 statements-n 省略可能です。引数 testexpression が引数 expressionlist-n のいずれかと一致するとき、一致した引数 statements-n のステートメントが実行されます。 解説 引数 testexpression が Case 節の引数 expressionlist のいずれかの式に一致すると、Case 節の次のステートメントがその次の Case 節まで実行されます。Case 節が最後の節の場合は、End Select まで実行されます。ブロックの実行が終わると、制御は End Select の次のステートメントに移ります。引数 testexpression が複数の Case 節に一致するときは、最初に一致した Case 節に続くステートメントだけが実行されます。 Case Else 節を使用して引数 testexpression がどの Case 節の引数 expressionlist にも一致しなかったときに実行する引数 elsestatements を指定します。Case Else ステートメントは必ずしも必要ではありませんが、予測できない引数 testexpression の値を処理するために、Select Case ブロックに Case Else ステートメントを記述することをお勧めします。どの Case 節の引数 expressionlist も引数 testexpression と一致しない場合に Case Else ステートメントが存在しないと、End Select の次のステートメントまで実行が継続します。 ------ 引用 ここまで この引用内容でわかったかと思います。 例も載っているので1度ヘルプを確認してみてください。 > CASEの「何もしない」という処理を2つのフィールドにするところがキーポイントで間違いないでしょうか キーポイントになりますでしょうか。 IF 文で考えると、、、 ま、何もしない記述の仕方ということで。 脱線) > (実際にはすごい早くなっていました) #4に書いたものだけでは、そう早くはならないと思います。 影響が大きかったのは、 > 個人Tの連番フィールドにインデックスあり(重複あり)を設定し、 また、 レコードセットをオープンする際に指定するカーソルの種類、 さらに レコードセットを得る時に絞り込み抽出しておく(Filter で処理するレコード数を減らしておく) だと思います。 Sample7 では adOpenForwardOnly Sample77 では adOpenKeyset カーソルの種類の違いは、以下を参照してください。(表示された前後も一緒に) (と言って、私は上記2種類しか使ったことないのですけど:今の私では自分の言葉で説明できるかどうか) http://msdn.microsoft.com/ja-jp/library/cc407887.aspx > 個人Tの連番フィールドにインデックスあり(重複あり)を設定し、 の設定は、 rs.Filter = "[連番] = 'XXXX" & rsUP("登録番号") & "'" の処理に大きく影響していると思います。 adOpenForwardOnly の時でも、Open する際の記述でWHERE条件となるフィールドに対してインデックスを付加することで早くなります。(だった?と) 得られるフィールド順を同じにしたいことからクローンを使ったと前記しましたが、adOpenForwardOnly ではクローンを使えないので、必然的に使ったことのある adOpenKeyset になった、という方が正しいのかもしれません。 (私が使ったことがある中でのこと) レコードセット内を探す場合、まずは Filter を使ってみる。これが私のスタイルです。 (今回のように1件しか該当しないものを探す場合でも) 今のところこれで間に合ってはいます。 遅かったら Find / Seek とかチューニングしていくと思います。 また、Select Case 部分を分岐(判別処理)しない形へ変形するとか。 Filter で書いてれば、処理の追加とか、し易いような気がします。 adOpenKeyset では、Filter 後で何レコードあるかわかるので、フィールドは重複ありなんだけど有効なデータには重複ないはず、と思っていても、2件以上のレコードがあればワーニングを出すとか、別の処理しながらデータをチェックするとかとか。 でも、それが書ける処理は微々たるものです。(めったにないのが本当かも) Filter を使うのは、私のスタイルだということで。 (記述内容に関して参考程度ということで:正しいとは断言できませんので)
お礼
ご回答ありがとうございます。 今回は複数のフィールドを対象にSELECT CASEしているので 実際には複数のフィールドが同時にCASE内部を通ってるわけですよね。 Select Case rsUP.Fields(i).Name ☆ ここで複数のフィールドを対象にして Case "登録番号", "連番" ☆ 1つめのCASEで"登録番号"と"連番"を「何もしない」処理で抜く Case Else ☆ rsUP.Fields(i).Value = rs.Fields(i).Value☆ それ以外の複数のフィールドにはCASE ELSEを実行する。 ネットで調べたりしたSELECT CASEだと数式や文字列式は対象が1つだったので、複数でも1つ該当すればすべてに当てはまると思ってしまっていました。これで納得できました。 脱線について Filterの働きは凄い大きいように思えます。実際のデータ量の1/3ぐらいにはなりました。(XXXXZZZZ絞込みなど) Filterとカーソルについてもっと勉強しておこうと思います。 ありがとうございました。
- 30246kiku
- ベストアンサー率73% (370/504)
なんか見たことある記述だったので。 その例を提示した本人になります。 既に回答も書かれて(解答が出て)いるので、ポイントはその方々に。 (私にはポイントいりません。) (ただ、役に立てたか補足なり書いて頂ければと思っています) (何も反応がないとムッとしたりしていますが) 以下に、余分なことも書きます。 ご質問の元になったのは以下となります。 http://oshiete1.goo.ne.jp/qa4863409.html 自分だけでコーディングして満足するレベルであれば、 sName = rsUP.Fields(i).Name If ((sName <> "登録番号") And (sName <> "連番")) Then rsUP.Fields(i).Value = rs.Fields(i).Value End If (このSample77 前の Sample7 では以下) sName = rsUP.Fields(i).Name If ((sName <> "登録番号") And (sName <> "連番")) Then rsUP(sName).Value = rs(sName).Value End If で十分なのですが、全体でコピー除外するフィールド名がわからなかったので、修正/追加しやすい形に記述していました。 (IF で記述した時に間違わずにしてもらえるのか?不安あり) sName に一度値を代入しているのは、rsUP.Fields(i).Name と書く箇所が複数あり、 そのたびに rsUP の Field(i) の Name と辿った処理される時間がもったいない?ような気がして。 If ((rsUP.Fields(i).Name <> "登録番号") And (rsUP.Fields(i).Name <> "連番")) Then また、 Select Case rsUP.Fields(i).Name Case "登録番号", "連番" の記述にすると、rsUP.Fields(i).Name を求めるのは1回だけで、"登録番号", "連番" と比較してもらえるのではないか、という思いもありました。 ※ Select Case を使ったのは、 修正/追加し易く、処理スピードもそこそこいけるのでは?というもの rsUP(sName).Value = rs(sName).Value の記述は、初めから rsUP.Fields(i).Value = rs.Fields(i).Value の記述でもいいんじゃないか、ということもありますが、Sample7 では rs / rsUP は同じ sSql を指定していますが独自にレコードセットを得ており、得られるフィールド順が同じ、と、私の中で確信持てていなかったので、フィールド名を使用し代入する形にしていました。(多分同じだと思いますが) Sample77 では、rs は rsUP のクローンとして扱っているため、得られるフィールドの順は同じであろう、ということで、何番目という i をそのまま利用しました。 rsUP(sName).Value 記述では、フィールド名を変えながらの処理になりますが、その名前を持つフィールドを探す処理が内部で行われていることと思います。 例えば、1つ目から sName であるかどうか、順次比較されていると思います。 ここの部分を少しでも早くするには、何番目、を直接指定してあげることです。 何番目を指定するには、得られたフィールド順が rs / rsUP で同じであることが必要です。 私の思惑と実際の動作がどうなっているのかは、わかりません。 また、私の思惑が正しいとは断言できません。 余談) 別の質問されてませんでした? 書ける状況だったらと、、、 でも、なくなったところを見ると解決されたんですね。
補足
ご回答ありがとうございます。 30246kikuさんには何度もお世話になってしまって申し訳ありません。 実行結果的にはフィールドのずれはなく登録番号だけ変わった状態になります。 記述を短くするだけでやはり気持ち早くなる感じなのですかね。 (実際にはすごい早くなっていました) >フィールド名を使用し代入する形にしていました フィールド名での記述で私としてはとても助かりました。理解しやすかったです。 CASEの「何もしない」という処理を2つのフィールドにするところがキーポイントで間違いないでしょうか
- imogasi
- ベストアンサー率27% (4737/17069)
#1でおっしゃるとおりだが テストしやすいエクセルで A列 B列(実行後) a a b BBB c BBB d AAAA e AAAA ーー Sub test02() For i = 1 To 6 Select Case Cells(i, "A") Case "a" Case "b", "c" Cells(i, "B") = "BBB" Case Else Cells(i, "B") = "AAAA" End Select Next i End Sub を実行してみて,考えてみてください。 該当したら、そのCaseから次のCaseまでに書いた処理を行う。何も書かずに次のCaseを続けたら、何も処理をしない。 ーー 上例ではA列が aなら何もしない<-質問者の疑問はこの場所か? b、cならB列にBBBを入れる<-疑問はこの場所か? 以上のa,b,c以外ならAAAを入れる。
お礼
ご回答ありがとうございます。 >該当したら、そのCaseから次のCaseまでに書いた処理を行う。何も書かずに次のCaseを続けたら、何も処理をしない。 ということは3つのCASEがあるとすると、必ず3つのCASEを通る。 ということで間違いないでしょうか? CASE1つ目に該当するからといってそこでSELECT CASEは終了にはならない。 これで間違っていなければすごいすっきりするのですが・・・
- hige_082
- ベストアンサー率50% (379/747)
>条件に当てはまった場合の処理を書く必要があると思うのですが 必ず必要ではありません IF文で表すと下のようになると思います ☆の部分をそのまま表すと、こんな感じではと思います If rsUP.Fields(i).Name = "登録番号" Or rsUP.Fields(i).Name = "連番" Then Else rsUP.Fields(i).Value = rs.Fields(i).Value End If 上を普通と言うか、一般的というかこんな感じになると思います If rsUP.Fields(i).Name <> "登録番号" And rsUP.Fields(i).Name <> "連番" Then rsUP.Fields(i).Value = rs.Fields(i).Value End If IF文ではちょっと長くて見づらいので、Select Caseで シンプルで見やすくしたのではと思います
お礼
ご回答ありがとうございます。 やはりCASEには「何もしない」という処理が存在するんですね。 #1の補足の考えであってますでしょうか? なるほど、CASEにすることによってすっきりしますね。
- nattocurry
- ベストアンサー率31% (587/1853)
何も書かないということは、「何もしない」という処理をさせる、ということであって、必ず何かを書かなければならない、ということではありあせん。 "登録番号"か "連番"の場合は、何もせず、それ以外の場合(Else)は、 rsUP.Fields(i).Value = rs.Fields(i).Value の処理をする、ということです。
補足
ご回答ありがとうございます。 1つ目のCASEで"登録番号"と"連番"2つのフィールドでのみ「何もしない」という処理をさせて、それ以外のフィールドは2つ目のCASEで処理を行う。 ということでよろしいのでしょうか?
お礼
ご回答ありがとうございます。 なるほど、下の処理をしているかと思いました。 X処理の後に次の処理。 Y処理の後に次の処理。 Z処理の後に次の処理。 すべてのCASEは2段構え・・・という感じでしょうか XとYとZ処理は同時に実行されることはないと言う事ですね