Functionプロシージャの戻り値が0になるバグの解説と対策

このQ&Aのポイント
  • Excel VBAでタイムスケジュールを作成する際、Functionプロシージャの戻り値が0になるバグが発生しています。
  • このバグは、繰り返し処理中に戻り値が意図せず0になってしまうことが原因です。
  • 解決策として、時間の比較には文字列ではなく数値を使用し、Select Case文の条件式を数値に修正することが挙げられます。
回答を見る
  • ベストアンサー

Function プロシージャの戻り値にバグ?

いつも拝見させていただいてます。 今回Excel VBAでタイムスケジュールを作成したところ、まったくわけのわからないエラーが発生してしまい途方に暮れており、皆様のお力をお借りしたく投稿させていただきます。 エラーの内容は簡単に言うと Function プロシージャの戻り値がなくなってしまう(0になっている)ことです。 ESC = ESColumn(EventStart) ---------------------------------- Function ESColumn(TimecoluConv As Date) As Integer Select Case TimecoluConv Case "8:00:00" ESColumn = 2 Case "8:10:00" ESColumn = 3 Case "8:20:00" ESColumn = 4 ・・・ End Select End Function と、このようなコードで入力された時間を数値に変換しているのですが、 繰り返し処理をしているといきなり戻り値が0になってしまいます。 今回は8:00を6回取得した後、8:10を変換しようとしたら戻り値が0になっていました。 戻り値を使用して、セルを選択するため、そのタイミングでエラーになります。 なぜ繰り返し処理の途中で発生するのでしょうか。 解説と対策をご教示していただけると大変助かります。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.8

Format関数のヘルプを見てもらえばわかることですが この書式指定では、時間部分は24時間制の2ケタです。 Select Case Format(TimecoluConv, "HH:mm:ss") Case "08:00:00" ESColumn = 2 Case "08:10:00" ESColumn = 3 Case "08:20:00" ESColumn = 4 ・・・ End Select End Function

legalist
質問者

お礼

訂正したら正常に機能しました! ご教示いただきありがとうございます。 エクセルのヘルプ見るべきでした。 初歩的な部分まで他人の知恵を借りる始末で申し訳ありません。 またお力をお借りすることがあると思いますが、よろしくお願いします。

その他の回答 (7)

  • mindatg
  • ベストアンサー率48% (110/227)
回答No.7

うん、回答者の皆が不明に思っているところがいまだに一切わかりません。 もう面倒くせぇので以下で処理しちゃえばいいんじゃないの Select Case TimecoluConv Case TimecoluConv Like "8:00*" ESColumn = 2 Case TimecoluConv Like "8:10*" ESColumn = 3 Case TimecoluConv Like "8:20*" ESColumn = 4

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.6

#2です。 > ESC = ESColumn(EventStart) そもそも、EventStartをどうやってループさせてますか? ”時分秒”の”秒”もCase文に必要?

回答No.5

VBAのDate型は、整数部で基準日からの日数、1日の時刻を小数点以下の実数で管理します。 実数なので時刻の最小単位は1秒ではありません。 また、文字列で指定した時分秒もDate型に変換したときに、秒単位の切りの良い値になるとは限りません。(誤差が出ます) 判定するDate型を秒単位の文字列に変換すれば誤差がなくなります。 Select Case Format(TimecoluConv, "HH:mm:ss") Case "8:00:00" ESColumn = 2 Case "8:10:00" ESColumn = 3 Case "8:20:00" ESColumn = 4 ・・・ End Select End Function

legalist
質問者

補足

ご回答ありがとうございます。 Hayashi_Trekさんのご教示の通りコードに加筆してみたのですが、エラーが取れません。(泣) 上記のコードで8:00 ~ 21:20まで実施したところ、 8:10 ~ 9:50までがうまくいきません。 時間が一桁という問題かと思ったのですが、8:00が問題ないことを説明できません。 モジュールをインポートし直してみたのですが、結果変わらずですし。。。 お力を貸していただいているのに泣き言言ってスミマセン。

  • mindatg
  • ベストアンサー率48% (110/227)
回答No.4

本来はOnErrorなりしておくべきなんですが 簡単な下記のようなステップだけ追加して確認してください Function ESColumn(TimecoluConv As Date) As Integer ESColumn = -1 ' 別の問題の場合は-1が返る Select Case TimecoluConv Case "8:00:00" ESColumn = 2 Case "8:10:00" ESColumn = 3 Case "8:20:00" ESColumn = 4 Case else ESColumn = 0 ' マッチしなかった MsgBox(TimecoluConv) '何が入ってきたのか表示する ・・・ End Select End Function

legalist
質問者

補足

ご回答ありがとうございます。 アドバイスに従い、TimecoluConvの中身を確認したのですが、他との違いが見受けられませんでした。 一度 End Selectの後にStopステートメントで格納された時間を確認しましたが、特に問題は見つけられませんでした。

  • jcctaira
  • ベストアンサー率58% (119/204)
回答No.3

legalistさん 単純なミスだと思います。 文字列("8:00:00")での比較は無理なので、「時刻」で比較してください。 Function ESColumn(TimecoluConv As Date) As Integer  Select Case TimecoluConv   Case #8:00:00 AM# または Function ESColumn(TimecoluConv As Date) As Integer  Select Case TimecoluConv   Case TimeValue("8:00:00") ご確認下さい。

legalist
質問者

補足

ご回答ありがとうございます。 コードの訂正ありがとうございます。 自分が最初に書いたコードでも機能したのですが、特定の時間(8:10 や8:20)のみ戻り値がなくなります。 説明が悪く申し訳ありません。

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.2

Case else を作って、stop書いておく

legalist
質問者

補足

ご回答ありがとうございます。 上記手順で停止させ、変数を確認しましたが、どれも問題ないようです。 (ESColumnは0になってますが) 8:20も同様の事象が発生するのですが、8:30は問題ないです。 なにかあるんでしょうか。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

TimecoluConv As Dateと文字列を比較していますよね? 8:10のつもりのTimecoluConvをよく調べたら、 8:10:01 とか 2/17 8:10 とかになっていて、"8:10:00"とは一致せずにて、全部のcaseを擦り抜けた、とかではないでしょうか?

legalist
質問者

補足

ご回答ありがとうございます。 自分も真っ先にそれを疑ったのですが、 他の時間との間で目立った違いはありませんでした。 入力もバーコードを使用しポカヨケしており、可能性としては薄いようです。

関連するQ&A

  • EXCELVBAでのFunctionプロシージャの戻り値について

    こんにちは。EXCELVBAの本を見てわからないことがあったので、教えてください。 まず、ソースコードは↓です Function P_OpenDatabase() As Integer On Error GoTo Err_Proc   Cn.ConnectionString=P_CnString()   Cn.Open Err_Proc:   If (Err.Number <> 0) Then     Call MsgBox(Err.Description)     Call MsgBox("データベースに接続できません")   End If   P_OpenDatabase = Err.Number…★ End Function で、わからないところは★の部分です 本の解説は↓です。 「プロシージャの戻り値を設定します。Errオブジェクトの「Number」プロパティにはエラーの番号が設定されているので、そのまま戻り値とします。処理が正常に行われたときには、Errオブジェクトの「Number」プロパティは「0(ゼロ)」になるので、戻り値も「0(ゼロ)」になります。」 僕が疑問に思っているのは処理が正常にされたとき(エラーがなかったとき)は、Err_Procの中の処理はされないので、戻り値には0が入らないのでは?と思ってしまうのですが。。 どうなんですかね?わかる方は教えてください。よろしくお願いします。

  • Functionプロシージャの便利さがわかりません

    私はVBAコードを作る時は、もっぱらsubプロシージャーを使ってしまうのですが、 http://excelvba.pc-users.net/fol5/5_4.html を参考に、 Functionプロシージャとsubプロシージャの違いを確認してみたのですが、 Functionプロシージャの便利さがわかりません。 *********************************** Sub Test() SubプロシージャとFunctionプロシージャのテスト i = 1 Call Subプロシージャ(i) i = Functionプロシージャ(i) MsgBox "Functionプロシージャ結果:" + CStr(i) End Sub Sub Subプロシージャ(ByVal i As Integer) MsgBox "Subプロシージャ結果:" + CStr(i) End Sub Function Functionプロシージャ(ByVal i As Integer) As Integer i = i + 1 Functionプロシージャ = i End Function *********************************** Functionプロシージャは、 (ByVal i As Integer) As Integer のように、、二回もデータ型(Integer)の指定をしなくてはいけないのでしょうか? リンク先の説明には、 「SubプロシージャとFunctionプロシージャの違いは Subプロシージャが引数を受け取るのみに対して Functionプロシージャは引数を受け取り、 戻り値を返すという関数としての役割を果たすことができる点です。」 と記載されてますが、 それはSubプロシージャでも出来てますよね? サンプルコードにおいてのFunctionプロシージャの便利さを教えてください。

  • プロシージャ内のコーディングについて

    VB6のプロシージャ内のコーディングについてですが、一般的にどちらのコーディンク方法を使用されていますか。 それとも全く違う方法を使用されてますでしょうか。 御意見をお願いいたします。 方法1 Function A() as Integer if 例外判定 then 例外処理 Exit Function End If 通常処理 End Function 説明 例外が発生したら例外処理をしてすぐにプロシージャを抜ける。 例外処理が多くなると途中でプロシージャを抜ける部分が多くなってしまう。 方法2 Function A() as Integer if 例外判定 then 例外処理 Else 通常処理 End If End Function 説明 例外が発生しても最後までプロシージャを抜けない。 必ず同じ場所でプロシージャを終了する。

  • Functionの戻り値を配列にしたいのですが

    vbを始めたばかりですがよろしくお願いします。 Functionの戻り値を配列にしたいのですが Function fnc(ByVal a As Byte, ByVal b As Byte) As Integer() fnc(0) = a + b fnc(1) = a - b End Function というような使い方はできないのでしょうか? 一つのFunctionで二つの計算結果をかえすには どうしたらよいのでしょうか? お願いします。

  • ストアドプロシージャの戻り値が取得できない

    ストアドプロシージャの戻り値が取得できない ストアドプロシージャ内でSelectとUpdateを行い、設定した戻り値をリターンしたいのです。 ついでにSelectとした複数行の結果の読み込みもしたいのですが。 Dim cmd As New System.Data.SqlClient.SqlCommand Dim i As Integer Dim readerA As System.Data.SqlClient.SqlDataReader cmd.CommandType = Data.CommandType.StoredProcedure cmd.CommandText = "SP名" cmd.Parameters.Add("A", System.Data.SqlDbType.Int) cmd.Parameters("A").Direction = System.Data.ParameterDirection.ReturnValue readerA = cmd.ExecuteReader() i = cmd.Parameters("A").Value if (i = 0) Then 処理 End If While readerA.Read() 処理 End While 上記でSelectした結果をreaderA("カラム名") で読みこめているのですが、戻り値Aの値が取得できていません。 ウォッチ式でcmd.Parameters("A").Valueを見るとNothingになっています。 ちなみに、違うストアドを実行しているところでは戻り値は取得できています。。。 ストアドがおかしいんでしょうか。Selectの取得結果も見ようとしているのがまずいのでしょうか。 環境はvb.net、SQLServer2005です。

  • プロシージャの戻り値を取得する方法

    perlからSQLPLUS->プロシージャを実行してその戻り値を取得。 戻り値が0なら次の処理へ、0以外ならエラー処理へというようなことをやりたいと思っています。 perlの実行コマンドは以下。 $sqlcmd = "sqlplus$DBUSER$PASS\@DB_ALIAS\@$SQLFILE $OUTFILE"; $sql_ret = system("$sqlcmd") >>8; この$sql_retにプロシージャの戻り値が入るようにしたいのです。 プロシージャを実行する$SQLFILEは以下のようなSQLです。 --------------------------------------------------- set serveroutput on WHENEVER SQLERROR EXIT 1 spool &1; DECLARE RetVal NUMBER; BEGIN RetVal := 実行ストアドファンクション; END; / spool off; EXIT SQL.SQLCODE; ---------------------------------------------- エラーが起きたときにファンクションは1を返すようにしているのですが、 それがSQLPLUSの実行結果の戻り値に反映されません。 どうしたらいいのでしょうか? よろしくお願いします。

  • oracleのfunctionで戻り値複数個

    oracleのストアドプロシージャのファンクションについてですが、 ファンクションは、戻り値を返すことができますが、 それを、複数個返すことはできるのでしょうか。 CREATE [OR REPLACE] FUNCTION ファンクション名(引数 IN データ型[, ...]) RETURN 戻り値の型 IS 宣言部 BEGIN 処理部 END ; お願いします。

  • Functionで戻り値を複数返す方法

    Functionで戻り値を複数取得したいのですが うまくいきません。(NULLの使い方が不正ですとエラー) 戻り値に配列を使う場合 呼び出し側はどのように記述すればいいでしょうか? <呼び出し側> Private Sub a() wkkekka1 = 処理結果(Kensu, Houhou)(0) ⇒ ここでエラー wkkekka2 = 処理結果(Kensu, Houhou)(1) wkkekka3 = 処理結果(Kensu, Houhou)(2) End Sub <関数> Public Function 処理結果(ByRef lngKensu As Long, ByRef strHouhou As String) Dim kekka(3) As Double If lngKensu = 1000 and strHouhou = aaaaaa then kekka(0) =  0.1 kekka(1) =  2   kekka(2) =  300 Else ↓ (省略)     ↓ End If 処理結果 = kekka End Function

  • Functionでの戻り値のとり方

    こんばんわ。 以下のように、Functionで引数に配列を指定して、戻り値も配列で取得したいのですが、方法としては以下のようにしかできないのでしょうか? ------------------------- '配列を宣言 dim Ary() as string dim AryRet() as string '戻り値の配列 Call Get_Ary(Ary(),AryRet()) ------------------------- Function Get_Ary(Ary() as string , AryRet() as string) 'Ary()を参照して、AryRet()を取得する End Function という風に書いているのですが、Functionのところを以下のように 書くのは無理でしょうか? うまく取れないというのはやっぱ無理なのかな・・ ------------------------- '配列を宣言 dim Ary() as string dim AryRet() as string '戻り値の配列 AryRet() = Get_Ary(Ary()) Function Get_Ary(Ary() as string) As string 'Ary()を参照して、AryRet()を取得する 'それを関数の戻り値とする Get_Ary = AryRet(index) End Function このように書くと、配列の最後のインデックスの値だけ取れてしまう ようなんですが、、やっぱ配列で返すというのは上記のやり方でないと 無理なのでしょうか? 詳しい方ご教示願います。

  • Functionの使い方が分かりません。

    ACCESS 2013環境でVBAを使用しています。 プログラムが長い上、使用する箇所が多くて困っています。 Functionで、使いたい時だけ呼び出したいのですが うまく行きません。 二つのテキストボックスに入力された、文字を組み合わせて 文字列を生成するプロシージャを作成しています。  txt1の値が、岡山  txt2の値が、オカヤマ の時 先頭の文字列が ア行、続きは _岡山 となるよう AscW関数で文字コードで一度抽出し, select文で判別しています。 コードは --------------------------------------------- Private Sub コマンド1_Click() Dim kanji As String Dim katakana As Integer Dim sento As String Dim hensuu As String kanji = Me.txt1 katakana = AscW(Left(Me.txt2,1)) Select Case katakana Case 12450 To 12458 sento = "ア行" Case 12459 To 12468 sento = "カ行" ~(中略)~    Case Else End Select hensuu = sento & "_" & kanji MsgBox hensuu End Sub --------------------------------------------- となっています。 Select Case文が長いのと、複数のフォーム上で実行させるボタンごとに 同じコードを記述していて、最近Accessの起動が遅くなってきました。 Select文をFunctionから呼び出し、最終的にはモジュールから呼び出しに 書き換えたいのですが、書き方が良く分かりません。 試したコード --------------------------------------------- Function moji(ByRef katakana As Integer,sento As String) Select Case katakana Case 12450 To 12458 sento = "ア行" Case 12459 To 12468 sento = "カ行" ~(中略)~    Case Else End Select End Function Private Sub コマンド1_Click() Dim kanji As String Dim katakana As Integer Dim sento As String Dim hensuu As String kanji = Me.txt1 katakana = AscW(Left(Me.txt2,1)) sento = moji(katakana) hensuu = sento & "_" & kanji MsgBox hensuu End Sub --------------------------------------------- 多分、大きく間違っているのではないかと思うのですが どのように修正したらよいでしょうか