アプリ版:「スタンプのみでお礼する」機能のリリースについて

ご相談します。

SqlDataReaderで「sum」を取得する際、0件の判定がうまくできません。

該当0件にも拘らず、読み込みが行えた時のステップが実行されてしまい、「System.InvalidCastException: '指定されたキャストは有効ではありません。'」が発生します。

しかし、「Select」文に「group by」を付けると、正しく、問題の該当ステップが回避されます。すでに、「where」句で対象レコードを絞り込んでいるため、「group by」をする必要はないため、「group by」は付けたくありません。

ネット検索しましたが、「group by」を付けなければならない話は見つけられませんでした。それとも、「sum」関数を使う場合の制約か何かがあるのでしょうか?

エラー発生:
String str_zan_Az = "select sum(UkeZan * Tnk * Rate / KeiQty) as AzKin_total from zan" +
" where ((ActNo = @ActNo_Az) and (Class = '00'))";
SqlCommand cmd_zan_Az = new SqlCommand(str_zan_Az, conn_JIP_HULFT_Dev);

SqlParameter parm_zan_Az = new SqlParameter("@ActNo_Az", SqlDbType.Char, 7);
cmd_zan_Az.Parameters.Add(parm_zan_Az);
cmd_zan_Az.Parameters["@ActNo_Az"].Value = reader_kyaku["ActNo"] as string;

using (SqlDataReader reader_zan_Az = cmd_zan_Az.ExecuteReader())
{
while (reader_zan_Az.Read() == true)
{
local_Azkin_total = local_Azkin_total + (decimal)reader_zan_Az["AzKin_total"]; <--- ここで、上記エラーが発生します
}
}

エラー発生しない:
String str_zan_Az = "select sum(UkeZan * Tnk * Rate / KeiQty) as AzKin_total from zan" +
" where ((ActNo = @ActNo_Az) and (Class = '00'))" +
" group by ActNo, Class"; <-- 「group by」を付けると、上記エラーが発生しません
SqlCommand cmd_zan_Az = new SqlCommand(str_zan_Az, conn_JIP_HULFT_Dev);

SqlParameter parm_zan_Az = new SqlParameter("@ActNo_Az", SqlDbType.Char, 7);
cmd_zan_Az.Parameters.Add(parm_zan_Az);
cmd_zan_Az.Parameters["@ActNo_Az"].Value = reader_kyaku["ActNo"] as string;

using (SqlDataReader reader_zan_Az = cmd_zan_Az.ExecuteReader())
{
while (reader_zan_Az.Read() == true)
{
local_Azkin_total = local_Azkin_total + (decimal)reader_zan_Az["AzKin_total"];
}
}

よろしくお願いします。

VisualStudio
Microsoft Visual Studio Professional 2017 (2)
Version 15.5.7
VisualStudio.15.Release/15.5.7+27130.2036
Microsoft .NET Framework
Version 4.7.03056

C#
Visual C# 2017 00370-20007-72734-AA238
Microsoft Visual C# 2017

SQL Server
Microsoft SQL Server Express (64-bit)
13.0.4206.0
Microsoft Windows NT 6.3 (17134)

PC
Microsoft Windows [Version 10.0.17134.165]

質問者からの補足コメント

  • うれしい

    kmeeさん

    お礼に書き漏らしましたので、こちらで補足します。

    今回の対応、本来は、計算前に、NULLやcount数を確認するのでしょうが、
    上記の確認を行わず、代わりに、Selectに「group by」を付けるというワークアラウンドもありという事ですね。

    「SqlDataReaderでの0件判定」の補足画像1
      補足日時:2018/07/23 11:31

A 回答 (2件)

SQL Server Management Studio はインストールしてありますか?


あるのなら、各SQLでどんな結果が返るか確認するのがいいかと。

groupの無い方は、whereで該当する0件の集計結果として、nullの行を返します。
ある方は、グループ毎に集計してwhereで該当するグループを返す(ように見える)ので、0行返します。

countで行数も数えて先に判定する、isnullで0にしてしまう、decimalにキャストするまえにnullかどうか確認する、などがかんがえられます。


ただ、手元で実行プランを確認したところ、groupの有無で、プランもパフォーマンスも違いはほとんどありませんでした。
    • good
    • 0
この回答へのお礼

kmeeさん

SQL Server Management Studioはインストールしてありましたので確認しました。(不慣れで、この様な使い方を思いつきませんでした)

「group by」しない方は、sum項目「MRF_total」が「NULL」にも拘らず、「(1行処理されました)」となっていました。このため、「while (reader_zan_MRF.Read() == true)」が成り立ってしまったと考えました。

それに対し、「group by」する方は、「(0行処理されました)」となるため、「while (reader_zan_MRF.Read() == true)」が成り立たなかったと考えました。

そして、『「group by」しない方は、1行処理され、NULL値が返されたが、
「group by」する方の「MRF_total」の空欄は、1行も処理されていない為、NULL値すら返されていない。』という事でしょうか?

丁寧な調査と優しい回答をありがとうございます。

大今

お礼日時:2018/07/23 11:17

>(decimal)reader_zan_Az["AzKin_total"];


詳しく見てないけど、NULLが返っているとかじゃないですかね?
慎重にキャストする、何かが足りない気がする。
    • good
    • 0
この回答へのお礼

回答をありがとうございます。

はい、おそらく計算項目がNULLのために、エラーになっていると思います。

そのため、「while (reader_zan_Az.Read() == true)」の中に計算式を配置して、読み込めた時のみ計算しようとしているのですが、該当なしの時にも「while (reader_zan_Az.Read() == true)」の中に入ってきてしまいます。

ところが不思議なことに、「group by」を付けると、該当なしの時に「while (reader_zan_Az.Read() == true)」の中に入って来ません。(「該当なし」が正しく認識されているようです)

しかし、本来(この件を除いては)「group by」を付ける必要性はないと考えているため、出来れば、「group by」を付けたくないのです。

お礼日時:2018/07/20 09:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

関連するカテゴリからQ&Aを探す