Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

dbの存在チェックの仕方 解決済み

タグの編集...

投稿者 ケンケン   (社会人)   投稿日時 2021/12/15 18:22:26
      Private m_dtUsers As DataTable

            Dim sql As String
            Dim dt As New DataTable
            Dim ct As Integer = 0

              sql = "  SELECT "
              sql += "   COUNT(*)"
              sql += " FROM tbl001"
              sql += " WHERE "
              sql += "       QRCODE = '" & sQRCode & "'"
              sql += "   AND HIZUKE_DATE = '" & sHizuke & "'"
              dt.Reset()
              DBAgent.GetDataTable(dt, sql) 
              Me.m_dtUsers = dt
              ct = Me.m_dtUsers.Rows().Count
                                                 ↑ データが存在しないのに1が入る
       
             何方かご教授お願いします.



      
 

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2021/12/15 21:05:19
DBAgent.GetDataTable という処理が何者かは分かりませんが、
件数を知りたいのであれば、
「ct = Me.m_dtUsers.Rows().Count」ではなく
「ct = CInt(dt.Rows(0)(0))」だと思います。


> データが存在しないのに1が入る
tbl001 の中身が 0 件であろうと 10 万件であろうと
 「SELECT COUNT(*) As cnt FROM tbl001 WHERE ~」
の結果は、常に 1 件だからです。

もしもこれが
 「SELECT COUNT(*) AS cnt, Col_1 FROM tbl001 WHERE ~ GROUP BY Col_1」
などであった場合は、結果が 0 件になることも 4 件になることも 1000件になることもありえます。


以下蛇足:

(1) COUNT(*) を得たいのであれば、
  DbDataAdapter.Fill よりも
  DbCommand.ExecuteScalar の方が望ましいです。
https://www.adonetvb.com/AdoNetExecuteScalarSql.html
※ ExecuteScalar は、先頭行の最初の列の値のみを返します。

(2) 文字列連結のためには、
  sql += ではなく
  sql &= を使うことが望ましいです。
https://docs.microsoft.com/ja-jp/dotnet/visual-basic/language-reference/operators/addition-assignment-operator

投稿者 ケンケン   (社会人)   投稿日時 2021/12/16 10:23:23
ご丁寧な回答ありがとうございます。
とても参考になりました。

お聞きした事が有ります。

何故
 件数を知りたいのであれば、
「ct = Me.m_dtUsers.Rows().Count」ではなく
「ct = CInt(dt.Rows(0)(0))」だと思います。
    ↑の書き方に至った考え方が私には良く分かりません
       何かヒントになる考え方が有りましたご教授お願いします。


ご指摘色々とありがとうございます。




投稿者 魔界の仮面弁士   (社会人)   投稿日時 2021/12/16 11:47:43
> お聞きした事が有ります。
お聞きした「い」ことがあります。かな。


まず大前提として、『SELECT COUNT(*) As cnt FROM tbl001』は、
WHERE の内容によらず「列数=1 ; 行数=1」な結果になることは分かりますか?

今回の SQL 結果は、dt.Rows.Count が 1 になることが明確ですので、
dt.Rows(0) で先頭行を得るという方法が使えました。結果が 0 件となる SQL の場合は
dt.Rows(0) を使うとエラーになってしまうのでご注意ください。


もしも SQL の内容が『SELECT NULL FROM tbl001』や『SELECT * FROM tbl001』などであれば
元の「Me.m_dtUsers.Rows().Count」で件数が得られます。
COUNT(*) する方法と比べると効率は悪いですけれどね。

それともう一つ。
Visual Basic では、引数を持たないプロパティの呼び出しでは
括弧を付けずに記述するのが一般的です。
そのため .Rows().Count や .Rows.Count() や .Rows().Count() ではなく、
.Rows.Count という表記を用いることをお奨めします。
※プロパティではなくメソッドの場合は、括弧を付けて呼び出した方が良いです。


> ↑の書き方に至った考え方が私には良く分かりません
まず、『DBAgent.GetDataTable(dt, sql)』とありますので、
SQL の実行結果を取得した DataTable 変数は dt ですよね。

なので、dt を見るのが手っ取り早いわけです。

データ取得後に、「Me.m_dtUsers = dt」という処理がありますので、
「dt.Rows(0)(0)」のことを
「Me.m_dtUsers.Rows(0)(0)」と書いても同じ意味にはなるのですが、
このケースでは、短く書ける方を採用しました。

今回のコードをさらに短く書きたければ、
 ct = CInt(dt(0)(0))
とすることもできます。
C# では .Rows を省略できませんが、VB では .Rows を省略できるためです。
(型付 DataSet という物を使えば、C# でも .Rows を省略できますが)


下記のコードは、いずれも「一行目の一列目の値」を得るためのコードです。
Dim x0 As Object = dt(0)(0)
Dim x1 As Object = dt.Rows(0)(0)
Dim x2 As Object = dt.Rows.Item(0)(0)
Dim x3 As Object = dt(0).Item(0)
Dim x4 As Object = dt.Rows(0).Item(0)
Dim x5 As Object = dt.Rows.Item(0).Item(0)



そして「Dim n As Integer = CInt(dt.Rows.Item(0).Item(0))」とは、下記のように分解することができます。
Dim a As DataRowCollection = dt.Rows   'DataTable のすべての行の一覧 
Dim b As DataRow = a.Item(0)  '行一覧の先頭行。Item は既定のプロパティなので「a(0)」表記も可。 
Dim c As Object = b.Item(0)  '行の先頭列の値。Item は既定のプロパティなので「b(0)」表記も可。 
Dim n As Integer = CInt(c)  'データ型を Object から Integer に変換 


投稿者 ケンケン   (社会人)   投稿日時 2021/12/16 12:33:29
スッキリです。