SQLServer2008とVB2010でログイン画面を作りたい

タグの編集
投稿者 社会人  (社会人) 投稿日時 2014/3/17 12:39:52

題名の通り、SQLseverにIDとパスワードが入力されたテーブルを元にVBでログイン画面を作りたいと思っています。

使用ソフト
・Microsoft SQL server 2008 Management Studio
・Microsoft Visual Studio 2010 Professional内のVisual Basic2010

使用PC
・XP SP3

現時点でSQLseverにユーザー情報というテーブルを作り、テーブル内に
・ID
・PASS
の二つの例があり、仮のIDとPASSを入れています。(IDはA、PASSはA)
IDを主キー設定し、IDとPASSのNULLを許可していません。

VBではFMLoginという名前でログインフォームを作成
・ID入力にtxtID、PASS入力にtxtPASSと名前を付けたTextboxが2個
・IDとPASSを入力した際に押すbtnGO、TextBoxに入力された内容を消す際に押すbtnClearのButtonが二個あります。
・ログイン成功の際は移動するフォーム名はfmMain


自分が知りたい情報は、IDとPASSが入力された前提でbtnGOを押した際にSQLserverに保存しているユーザー情報のテーブルから条件が合致した際はfmMainに移動するコードと、btnClearを押した際にFMLoginの初期画面を再度読み直すコードの二つが知りたいです。
再度読み直すコードは今回のデータベースプログラムでも使いたいと思っています。
宜しくお願いします。
投稿者 an  (社会人) 投稿日時 2014/3/17 13:02:46
> 自分が知りたい情報は、IDとPASSが入力された前提でbtnGOを押した際にSQLserverに保存しているユーザー情報のテーブルから条件が合致した際はfmMainに移動するコードと、
> btnClearを押した際にFMLoginの初期画面を再度読み直すコードの二つが知りたいです。

これら二つのボタンの処理は具体的にどこまでできていますか?
そしてそれのどこが分からないですか?
それとも何も分からないので何もできていない状態ですか?

ちなみに初期画面を再度読み直す必要があるのですか?
「btnClear」というボタンの名称からするとクリアだけできればよさそうに感じますが、
読み直す必要があるのであれば、FMLoginを表示した方法に依存しますので、
どうやって表示したかも提示してもらう必要があると思います。



投稿者 an  (社会人) 投稿日時 2014/3/17 13:14:26
追加の確認です。

> 再度読み直すコードは今回のデータベースプログラムでも使いたいと思っています。

これはどういう意味ですか?
「今回のデータベースプログラム」とは何を指してますか?



ちなみにDB周りの処理は以下を参考にできないでしょうか?
http://homepage1.nifty.com/rucio/main/dotnet/Samples/Sample033ConnectSQLServer.htm
当掲示板のサンプル集です。
これを見た上で具体的に質問してもらえると答えやすくなると思います。
投稿者 (削除されました)  () 投稿日時 2014/3/17 16:00:04
(削除されました)
投稿者 社会人  (社会人) 投稿日時 2014/3/17 16:05:20
anさん

すみませんanさん、名前が変わってますが複数条件検索のプログラムについて質問した名無しと同一人物です。
久しぶりにこのサイトに来たので名前を忘れていました。

現状はこうなっていまして、Textboxの内容をSQLserverにどう参照させるかが分かりません。


Imports System.Data.SqlClient

Public Class fmLogin
    Private cnstr As String = "Data Source=user;Initial Catalog=データベース;Integrated Security=True"
    
    Private Sub fmLogin_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        TextBox3.Text = "※ココにメッセージが表示されます"
    End Sub

    Private Sub btnGO_Click(sender As System.Object, e As System.EventArgs) Handles btnGO.Click
        If txtID.Text.Length > 0 And txtPASS.Text.Length > 0 Then
        Else
            TextBox3.Text = "ユーザー名とパスワードは必ず記入して下さい"

        End If
    End Sub
End Class

※最初の書き込みで説明がありませんが、fmLoginフォームの一番下にtextbox3.Textを使用し、メッセージの表示専用としています。


今回のデータベースプログラムとは何かとありましたが、最初に触れましたが複数条件検索プログラムにも応用したいと思っています。
今は、全てのTextboxにClearを使っていますが約20個以上もClear指定するよりも手っ取り早いと考え尋ねています。

サンプル集を見ましたが、現時点で自分が欲しい情報が見つかりませんでした。
投稿者 kiku  (社会人) 投稿日時 2014/3/17 16:45:36
    Private Sub btnGO_Click(sender As System.Object, e As System.EventArgs) Handles btnGO.Click
         If txtID.Text.Length > 0 And txtPASS.Text.Length > 0 Then
      ●ここにプログラムを追加します。
         Else
             TextBox3.Text = "ユーザー名とパスワードは必ず記入して下さい"

         End If
     End Sub

上記の●印のところに、プログラムを追加していきます。
●印のところには、下記を行う必要があります。

1.txtID.Textをキーとして、データベースに
  問い合わせを行い、対応するパスワードを持ってくる。
  ※対応するパスワードが無い場合もある。

2.データベースからもってきたパスワードと、txtPASS.Textを
  比較し、パスワードが合致しているか判定する。

3.パスワードが合致していれば、fmMainを起動する。

上記1については、すでに返答が付いている通り、
http://homepage1.nifty.com/rucio/main/dotnet/Samples/Sample033ConnectSQLServer.htm
を参照してください。
わからなければどこがわからないのか教えてください。

上記2については、比較するだけですので
わかると思います。
わからなければどこがわからないのか教えてください。

上記3については、
http://dobon.net/vb/dotnet/form/showform.html
を参照してください。
わからなければどこがわからないのか教えてください。
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/3/17 17:03:52
少し、質問を。
・ID、PASSでOKとなった場合、frmMainを表示しますが、元のFMLoginをどうするのですか?
 そのまま表示しておくのでしょうか?それとも非表示にするのでしょうか?あるいは・・・
・btnClearボタンはFMLoginにあるのでしょうか?
 であるなら、ログイン成功時にfrmMainを表示してからもFMLoginを操作できる必要がありますね?
  それともログイン前に単にID、PASSをクリアするだけでしょうか?

接続に関してはkikuさんが書かれてるところを参照すれば、解決するでしょう。
検索について
a)IDだけで検索して、PASSを取得し、入力値と比較し判定する。
b)IDとPASSで検索し、結果取得の有無で判定する。
ぼくは、これまでb)を使ってきましたが、セキュリティとか実際のところはどうなんでしょうね^^;
投稿者 kiku  (社会人) 投稿日時 2014/3/17 17:17:31
>検索について
>a)IDだけで検索して、PASSを取得し、入力値と比較し判定する。
>b)IDとPASSで検索し、結果取得の有無で判定する。
>ぼくは、これまでb)を使ってきましたが、セキュリティとか実際のところはどうなんでしょうね^^; 

プログラム的には、b)に方が簡単ですね。勉強になります^^;
セキュリティ的には、a)もb)もパスワードをやり取りしているので
傍受できるとしたならば同じかと思います。
SQLServerの場合はSSLを利用できるみたいですね。
これを使えばセキュリティは向上すると思います。
投稿者 an  (社会人) 投稿日時 2014/3/17 17:21:43
> 名前が変わってますが複数条件検索のプログラムについて質問した名無しと同一人物です。
> 久しぶりにこのサイトに来たので名前を忘れていました。

やはりそうでしたか。
その旨一言最初にあればなお良かったのですが^^;
できればユニークになる名前に変えた方が望ましいですね。



> 現状はこうなっていまして、Textboxの内容をSQLserverにどう参照させるかが分かりません。

これについては前回の複数条件検索のプログラムが理解できていれば基本的にはできるはずです。
ただ一部毛色が異なるのでそこだけ解説します。

基本的に前回も今回もデータの照会・照合なのでSQLのSELECT文を使用します。
前回のは条件(Where句)が入力内容によって変動しますが、
今回は条件(Where句)の中の対象項目は変動せず、入力値の部分だけ変わるので
そこは簡素化された形になると思います。
また取得内容として前回のは一覧形式だったので
SQL文→SqlDataAdapter→DataTableと変換させて最終的にDataGridに表示させていたと思いますが、
今回は単純に対象のレコードがあるか(1件か0件か)を判断すれば良いわけです。
条件に入力された値をセットし、レコードが取得できるかと判定しても良いですし、
SQLの集計関数のCount(*)を使用しても良いと思います。

Count(*)を使う場合のサンプル
http://code.msdn.microsoft.com/windowsdesktop/DataAccess-howto-7ad051b1

※個人的にはログインした後にログインしたユーザーの情報により
 その後の処理・設定を変えるという事が想像できるので、
 レコードを取得した方が良いとは思いますが・・・。


> サンプル集を見ましたが、現時点で自分が欲しい情報が見つかりませんでした。 

基本的にはプログラマが使用したい情報が100%に載っている事はないと考えた方が良いでしょう。
そのまま使えるというケースもありますが、基本的にはそのまま使う事は色々な意味で個人的にはありえません。
・アルゴリズムは要件と一致しているが、コーディングルール(命名規則等)が違う。
・そのまま使う=理解をしていない=今後何か問題が発生した時に応用が利かない。
・著作権的なものはそのまま使っても問題ないか?
・etc

とりあえず先ほどお伝えした
http://homepage1.nifty.com/rucio/main/dotnet/Samples/Sample033ConnectSQLServer.htm
にある程度の情報はあるはずです。
上記Count(*)のサンプルとも類似していますが、理解して改造すれば使えるはずです。
今回最低でも改造する部分としては
・SQL文
・取得した後の処理(MsgBoxではなく条件文(If))
・etc
まずはSystem.Data.SqlClient.SqlCommandクラスとそのクラスのExecuteScalarメソッドあたりについて
勉強してみてはいかがでしょうか?




> 今回のデータベースプログラムとは何かとありましたが、最初に触れましたが複数条件検索プログラムにも応用したいと思っています。
> 今は、全てのTextboxにClearを使っていますが約20個以上もClear指定するよりも手っ取り早いと考え尋ねています。

そういう意味でしたか。
やり方は色々ありますが、.NET側が用意している共通処理として自分は知りません。
また初期化と言ってもクリア(=テキストが空)のケースもあれば、既定の文字(「0」等)が入る場合もありますので。
その用件に合わせて最適なものを作るのがプログラマの腕な気がします。

とりあえずクリア(=テキストが空)しかないというのであれば以下のような形かと思います。

(1)クリア用メソッドを作ってそこで全てのテキストボックスをClearメソッドを呼び、
 画面ロード時やクリアボタン押下時等必要に応じてに呼び出す。
(2)フォーム上の全てのコントロールをMe.Controlsより取得し、
 対象がテキストボックスならClearメソッドを呼ぶ。
 ※Me.ControlsではGroupBoxコントロール等のコンテナコントロールの上に乗っているコントロールは
  取得でいないので考慮が必要。
 ※クリアしたくないコントロールもクリアされる可能性があるので考慮が必要
(3)基本的には(2)の派生した考え方になるが、
 対象のコントロールをMe.Controlsを使用せずに、List(of T)等に事前(フォームコンストラクタ等)に設定し、
 それをループで回してClearメソッドを呼ぶする。

それぞれ一長一短だと思いますが、個人的にはご自身が理解できるレベルで行うのが一番だと思います。
基礎的なものが理解できたら、一つ上の・・・という感じで。
コレクション、ForEach、再帰処理、ジェネリックコレクション等が理解できている様であれば、
(2)または(3)で、理解できていないようであれば(1)が良いと思います。
また、その時々ではありますが、自分が作る時も(1)でやるケースが多いと思います。


とりあえずは文章のみでコードは書きませんでしたが、
全体像を理解した上で細かな点が分からないようであれば、
必要に応じてコードにて説明しようと思います。



ちなみに質問が複数ある場合は別々にした方が良いですね。
質問する側も回答する側も今後似たような問題が発生して参照する側も
分かりやすくなると思いますので。

投稿者 社会人  (社会人) 投稿日時 2014/3/19 13:56:34

Hideさん
・FMLoginはどうするのですか?
ログインに成功した後のFMLoginのみ終了して、FmMainはそのまま作業が出来る仕組みにしたいです。

・btnClearの場所
ログイン成功後のFMLoginの操作は不可として、指摘通りIDとPASSのTextboxをクリアするだけの仕組みです。

・検索について
自分のイメージとしては、b)の検索方法を考えています。

Kikuさん
anさん

説明有難うございます。
試しに、教わったプログラムコードを(複数条件検索のプログラム)ベースに作ってみましたが、正しいIDとPASSを入力しなくてもコードが不十分のせいでFmMainに移動しています。
後、ログイン成功後にFmLoginを隠すコードを入力しましたがFmMainの画面で右上にある「最小化、最大化、閉じる」ボタンの閉じるボタンを押すとFmMainは消されますが、VBのソフト上ではプログラムの実行中になったままになっています。


Imports System.Data.SqlClient

Public Class fmLogin
    Private Sub fmLogin_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        TextBox3.Text = "※ココにメッセージが表示されます"
    End Sub

    Private Sub btnGO_Click(sender As System.Object, e As System.EventArgs) Handles BtnGO.Click
        Dim DB As String = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"
        Dim sql As String
        sql = "SELECT * "
        sql += "FROM T確定ユーザー情報"
        If txtID.Text.Length > 0 And txtPASS.Text.Length > 0 Then
            sql += " WHERE (ユーザー名 Like '" & txtID.Text & "%')"
            sql += " AND (パスワード Like '" & txtPASS.Text & "%')"
            fmBase.Show()
            Me.Hide()
        Else
            TextBox3.Text = "ユーザー名とパスワードは必ず記入して下さい"

        End If
    End Sub
End Class
投稿者 an  (社会人) 投稿日時 2014/3/19 14:51:56
> 試しに、教わったプログラムコードを(複数条件検索のプログラム)ベースに作ってみましたが、正しいIDとPASSを入力しなくてもコードが不十分のせいでFmMainに移動しています。

        If txtID.Text.Length > 0 And txtPASS.Text.Length > 0 Then
             sql += " WHERE (ユーザー名 Like '" & txtID.Text & "%')"
             sql += " AND (パスワード Like '" & txtPASS.Text & "%')"
             '★ 
             fmBase.Show()
             Me.Hide()
         Else
             TextBox3.Text = "ユーザー名とパスワードは必ず記入して下さい"

         End If

これでは条件が一致しようがしまいがfmBaseをShow()してますよね?
SQL文を構築してるだけで、そのSQL文が実行されていません。
上記の★の位置に正しかった時のみfmBaseをShow()するようにする必要があります。
そのやり方が前回伝えた
http://homepage1.nifty.com/rucio/main/dotnet/Samples/Sample033ConnectSQLServer.htm
に記載されています。

SqlConnectionクラスとSqlCommandクラスを利用し,
ExecuteScalarメソッドで情報を取得します。
もし取得できたら次画面を表示し、できなかったらメッセージ等を表示するようにすれば良いと思います。

> 後、ログイン成功後にFmLoginを隠すコードを入力しましたがFmMainの画面で右上にある「最小化、最大化、閉じる」ボタンの閉じるボタンを押すとFmMainは消されますが、VBのソフト上ではプログラムの実行中になったままになっています。
FmLoginはHideしているので見た目上なくなっていますが、
内部的には残っています。
なので実行中は正しいわけです。

FmMainの閉じるボタンを押した場合どうしたいかによって処理が変わりますが、どうなのでしょうか?
・ログイン画面に戻る
→Hideしていたログイン画面を再度Showする必要があります。
・アプリケーションを終了する
→Hideしていたログイン画面をCloseする必要があります。
・その他
→???


また、提示されたソースコードをみたところ根本的な部分について理解が足りないようです。
新しい画面に遷移する場合、直接Showするのではなく、
一回変数にNewをしてからするべきなのですが(諸説あります)
その辺を行っていないという事はもう少し勉強が必要かと思います。
本サイトの 初級講座の第29回 2つ目のフォームにて勉強してみてはいかがでしょうか?
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard29.htm
上記第29回に限らず、初級講座は基本的な事項が含まれていますので、
一通り理解することをお勧めします。

投稿者 社会人  (社会人) 投稿日時 2014/4/9 11:56:52
遅くなってすみません。

自分なりに試し、エラーが発生していますがイメージとしてはこれで良いのでしょうか?

Imports System.Data.SqlClient

Public Class fmLogin
    Private Sub fmLogin_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        TextBox3.Text = "※ココにメッセージが表示されます"
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim DB As String = "Data Source=user;Initial Catalog=データベース;IntegratedSecurity=True"
        Dim sql As String
        sql = "SELECT * "
        sql += "FROM ユーザー情報"
        If TextBox1.Text.Length > 0 And TextBox2.Text.Length > 0 Then
            If sql += " WHERE (ユーザーID like '%" & TextBox1.Text.Trim & "%')" and sql += " WHERE (パスワード like '%" & TextBox1.Text.Trim & "%')"
                Dim Base As New fmBase
                Base.Show()
        Me.hide()
            Else
                TextBox3.Text = "入力した情報が間違ってます。もう一度確認してから入力して下さい"
            End If
        End If
    End Sub
End Class

・FmMainの閉じるボタンを押した場合どうしたいか
そのままアプリケーションを終了する流れにします
FmMainの閉じるコードを以下にした所、成功しました

Private Sub fmBase_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        Application.Exit()
    End Sub

後、現在FmLogin以外のフォームで質問したい事がありますが、こちらの掲示板は一人の質問者が問題が解決しないまま新しい質問をしても大丈夫でしょうか?
投稿者 an  (社会人) 投稿日時 2014/4/9 12:30:53

> 自分なりに試し、エラーが発生していますがイメージとしてはこれで良いのでしょうか?

何をもって「イメージ」とするかにもよりますが,
・If文としてのイメージならOK(?)
・SQLとしてのイメージならNG
といったところでしょうか?

前回・前々回もいいましたが、
SQL文は構築していますが、そのSQLを実行していません。
【プログラムイメージ】
        If TextBox1.Text.Length > 0 And TextBox2.Text.Length > 0 Then
             'ここでSQL文を実行しDBの結果を得る 
             If 【上記SQLでのDB取得結果が正常(UserIDとパスワードが正しい)だったらという条件にする】 Then



また、If文中での+=はおかしいです。
他にもおかしいところは多々ありますが、まずはSQLを実行する事を理解するようにしてみてください。

理解できていないようであれば、
いきなり自分がやりたいことに組み込まずにまずはSQLを実行するにはどうすれば良いか
という点について理解するために、
参考サイトの「1.SQL Server認証で接続する例」をコピペし、自分の環境にあった内容に書き換えます。
書き換える点はSQL文(主にテーブル名や列名等)とDBへの接続情報(UserID等)になります。
それらを色々変更してみて動きを肌で感じてみてはいかがでしょうか?



> 後、現在FmLogin以外のフォームで質問したい事がありますが、
> こちらの掲示板は一人の質問者が問題が解決しないまま新しい質問をしても大丈夫でしょうか?

管理人ではないので間違っているかもしれませんが、
問題の内容が異なるようであれば、特に問題はないと思います。
しかし、今の現状を考えると複数の事案を抱えると逆に混乱するだけでは?と個人的には思います。
本課題を理解した上での方が良いかと。

投稿者 HiDE-Ada  (社会人) 投稿日時 2014/4/9 16:42:06
回答があったのに気づきませんでした、失礼しました。
ログインボタンをクリックした時の処理を整理してみましょう。
1.IDとPASSの両方に値があるかチェックする。
 いずれかになければ、ExitSub …必要ならメッセージを表示する。
2.IDとPASSをパラメータとした、DB検索ファンクションを実行する。
 その結果がOKなら、次の画面を表示する。
 NGなら、ExitSub …必要ならメッセージ等を表示する。
になるかと思います。

1.の部分は出来ているようですが、流れをはっきりさせるために
if TextBox1.Text.Length = 0 orelse TextBox2.Text.Length = 0 then
    'メッセージ表示 
    ExitSub
endif

として、一度ブロックを終了した方がわかりやすいかと思います。

2.ですが、こんな感じでしょうか?
if checkLogin(TextBox1.Text, TextBox2.Text) then
    'OKの場合の処理 
else
    'NGの場合の処理、 
endif


そして、新しく作るcheckLoginですが、
1.検索SQL文を作成する。
2.DBへ接続する。
3.検索SQL文を実行し、結果を得る。
4.DBを切断する。
5.結果を返す。OKならTrue、NGならFalseでいいかと思います。
この部分はDB関係なので、いろんなところにサンプルがあると
思いますので、検索してみて下さい。

C言語での古い話ですが、1関数は30行程度にすべきだということを
聞いたことがあります。
30行はスクロールせずに画面表示できる量ってことです。
まぁ30行は言いすぎだとは思いますが、長すぎる関数は何をしているか
わかりづらくなり、修正も面倒になってきます。
場合によっては数行でも、別メソッドにすることで呼び出し元が簡潔に
なれば、よいと思っています。
投稿者 社会人  (社会人) 投稿日時 2014/4/9 18:01:06
>anさん
指摘有難うございます。
試しに作ってみたんですが、コード中央の※マークの箇所が何を示しているのか分かりません。
コード自体にエラーは無いのですが、得意先データベースに無い値を入力してもMsgBoxで表示されます。
どうしたら良いでしょうか?

Dim St As String
        Dim Cn As New System.Data.SqlClient.SqlConnection
        Dim SQL As System.Data.SqlClient.SqlCommand
        Dim ServerName As String = "Data Source=user;Initial Catalog=データベース;Integrated Security=True"
        Dim DatabaseName As String = "得意先データベース"

       ※ St = "Server=""(local)"";"
       ※ St &= "integrated security=SSPI;"
        St &= "initial catalog = 得意先データベース"

        Cn.ConnectionString = St

        SQL = Cn.CreateCommand

        SQL.CommandText = "SELECT 4000 FROM ユーザー情報"

        Cn.Open()

        MsgBox(SQL.ExecuteScalar)

        Cn.Close()
        SQL.Dispose()
        Cn.Dispose()

>HiDEさん
検索SQLに関してですが、これでも大丈夫でしょうか?

Dim cnstr As String = "Data Source=user;Initial Catalog=データベース;Integrated Security=True"
        Dim sql As String
        sql = "SELECT * "
        sql += "FROM 得意先データベース"
(ifなど中略)
 sql += " WHERE (取引先コード Like '%" & TextBox1.Text.Trim & "%')"
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/4/10 01:35:10
えーと、ちょっとこんがりましたね。
検索SQLと書いてしまいましたが、ログインの検索のつもりでした。
このログイン検索については、ご自分で上に書かれている内容でほぼ
問題ないですが、CommandTextは

SELECT count(ID) FROM ユーザ情報 WHERE ID = 'xxxx' AND PASS = 'yyyy'

のような形になります。
xxxxやyyyyに入力値が反映するように編集します。
checkLoginというメソッドにしたなら、そのパラメータを使用してSQL
文を作成します。
このWHERE句にLIKEを使うのはふさわしくないです。

上で質問されている※の部分は接続文字列と言われるものです。
対象DB…SQLServer、Oracle、MySql等や認証方法で異なります。
上記の記述でもMsgBoxまで動作しているなら、問題ないと思います。
ServerNameに設定されているものも、接続文字列ですね。

ちなみに、MsgBox…MessageBox.show?が表示されるのは、
CommandTextに設定しているSQL文にWERE句がないからです。
ExecuteScalarは結果セットの最初の行の最初の列の値が
返されるので、4000という値が返されることになります。

検索SQLはこれまでのとおりで問題ないのではないでしょうか?
厳密に言えば、SELECT句で*は使わない方がいいです。
投稿者 an  (社会人) 投稿日時 2014/4/10 11:04:00
> 試しに作ってみたんですが、コード中央の※マークの箇所が何を示しているのか分かりません。
>       ※ St = "Server=""(local)"";"
>       ※ St &= "integrated security=SSPI;"
>       St &= "initial catalog = 得意先データベース"

以前入力内容で条件付けしてDataGridViewに表示する方の質問の方では
(http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=15515)
> Dim cnstr As String = "Data Source=user;Initial Catalog=データベース;Integrated Security=True"
とやっていたので、こちらと同じ指定でいいのではないでしょうか?
SQLServerは環境なく、また経験が少ないので良くわからないのですが、
前回の質問の時と同じ指定で良いのでは?と思います。



> コード自体にエラーは無いのですが、得意先データベースに無い値を入力してもMsgBoxで表示されます。

MsgBoxには何が表示されるのでしょうか?
If等で条件分岐をしていないので、表示されるのは当然です。
今回のサンプルプログラムでは何が表示されたか(取得されたか)が重要になりますので、
それを伝えてもらわないと何とも言えません。
とはいえHiDE-Adaさんが仰っているように、「4000」が表示(取得)されたと推測できますが、
推測で進めると良い方向に進みませんので。

とりあえず
> SQL.CommandText = "SELECT 4000 FROM ユーザー情報"
となっていますが、
うまく行ったらこれにHiDE-Adaさんが仰っているような「Where句」を追加してみてください。
(入力値はとりあえずはTextBox等でなくてもよく直接プログラム上に記入でも良いと思います。)

投稿者 社会人  (社会人) 投稿日時 2014/4/18 10:33:36
遅くなってすみません。

  Dim St As String
        Dim Cn As New System.Data.SqlClient.SqlConnection
        Dim SQL As System.Data.SqlClient.SqlCommand
        Dim ServerName As String = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"
        Dim DatabaseName As String = ""

        St = "Server=""(local)"";"
        St &= "integrated security=SSPI;"
        St &= "initial catalog = データベース"

        Cn.ConnectionString = St

        SQL = Cn.CreateCommand

        If SQL.CommandText = "SELECT * FROM ユーザー情報 WHERE ユーザーID = 'txtID.text' and パスワード = 'txtPASS.text" Then
            MessageBox.Show("A")
        End If
        Cn.Open()
    
    SQL.Connection = Cn
        ※MsgBox(SQL.ExecuteScalar)

        Cn.Close()
        SQL.Dispose()
        Cn.Dispose()

というコードを入力しましたら※の部分で

InvalidOprerationExceptionはハンドルされませんでした
ExecuteScalar: CommandText プロパティは初期化されていません。

と出てきました。
このエラーはSqlSeverにあるデータベースに接続が失敗したのか、それとも接続自体は成功しているがその後の処理が失敗したのか、根本的に何かが違っているのでしょうか?

>「4000」について
お二人が言ってる通り、プログラムの実行後に4000とMsgBoxが表示されます。
SQL.CommandText = "SELECT ※ FROM ユーザー情報"
※の部分がそのままMsgBoxに表示される形になっていました。

>anさん
文章を見てる限り、以前教わった下の方法を上手く使いこなすとデータベースの接続とtextboxに入力された情報とSqlServerに保存している情報を照り合わせてログインが出来ると言う認識で当たっていますか?

Dim DS As String = "Data Source=user;Initial Catalog=データベース;Integrated Security=True"
        Dim sql As String
        sql = "SELECT *"
        sql += "FROMTユーザー情報"
(以下略称

>HiDE-Adaさん
すみません。前回のSQLは他のフォームから直接コピーして修正する前に書き込んでしまいました。
今回のSQLで大丈夫でしょうか?

投稿者 an  (社会人) 投稿日時 2014/4/18 12:46:46
>>anさん
> 文章を見てる限り、以前教わった下の方法を上手く使いこなすと
> データベースの接続とtextboxに入力された情報とSqlServerに保存している情報を照り合わせて
> ログインが出来ると言う認識で当たっていますか?

そうです。その通りです。
1文で済まそうとするとその通りなのですが、プログラムでは基本的には噛み砕いて記述する必要があります。
(ある程度の処理をまとめて行う事も可能なケースもありますが、それは理解が進んでから行う必要があります。)

今回の処理を噛み砕いて説明すると以下の通りになります。

(1)データベースに接続する。
(2)データベースに情報を問い合わせ、情報を取得する。
(3)データベースとの接続を切断する。
(4)データベースに情報を問い合わせて取得した結果を処理する。

これは概要であってさらに噛み砕くと以下の通りになります。

(1)データベースに接続する。
 a)接続文字列を生成する。
 b)接続する。
(2)データベースに情報を問い合わせ、情報を取得する。
 a)問い合わせ用文字列を作成する。(SQL文を組み立てる)
 b)問い合わせ用文字列実行し、実行結果を得る。
(3)データベースとの接続を切断する。
 a)接続文字列を生成する。
(4)データベースに情報を問い合わせて取得した結果を処理する。
 a)(2)のb)で得た結果を判断する。
 b)上記a)の判断で正しいと判定されたら、次の画面を表示する。(ログイン処理の場合)
 b)上記a)の判断で正しいと判定されたら、本画面を非表示にする。 (ログイン処理の場合)

さらに噛み砕くとNewするとか破棄するとかもありますが、省略します。


上記点を踏まえまして、

>    If SQL.CommandText = "SELECT * FROM ユーザー情報 WHERE ユーザーID = 'txtID.text' and パスワード = 'txtPASS.text" Then
>        MessageBox.Show("A")
>    End If
>    Cn.Open()
>    SQL.Connection = Cn
>    MsgBox(SQL.ExecuteScalar)
>    
> というコードを入力しましたら※の部分で

> InvalidOprerationExceptionはハンドルされませんでした
> ExecuteScalar: CommandText プロパティは初期化されていません。

> と出てきました。
> このエラーはSqlSeverにあるデータベースに接続が失敗したのか、
> それとも接続自体は成功しているがその後の処理が失敗したのか、根本的に何かが違っているのでしょうか?

とのことですが、まず発生したエラーを理解しましょう。
「InvalidOprerationException」は読んで字のごとく、オペレーションが正しくない時に発生する例外です。
その詳細としてExecuteScalarを実行した時にCommandText プロパティ(SQL文)が初期化されていない(空)と言っています。
その前で行っているCommandText プロパティに関連する処理を見ると
> If SQL.CommandText = "SELECT * FROM ユーザー情報 ~略~" Then
とやっています。
VBでのIf文での = は代入ではなく比較になりますので、これではCommandTextプロパティには設定されませんので初期化されていない状態となり、今回の例外が発生したことになります。

また、先に説明した噛み砕いた説明を考えると、
問い合わせの実行(SQL.ExecuteScalar()メソッド)と取得結果の確認(If文)の処理の順序が逆ですよね?
その辺も考え方として理解されていないものかと思われます。
まずは、先に説明した噛み砕いた説明の(1)~(3)までを理解しないと
本来のメインである(4)でのログイン処理というものが行えないと思いますので、
If文などは使わずに、データベースから値を取得するという処理について
完全に理解した方が良いともいます。

また、理解するにあたって、とりあえずはテキストボックスなどは使用せずに
「ユーザーID = '001'」のように書いて理解することを中心にすることをお勧めします。
その理解が出来てからでないと、ただただ混乱するだけだと思います。


個人的な話ですが、自分も10年以上プログラムは書いていますが、
新しい事を理解する時は1行~10行程度のものを作っては動かし、作っては動かしとやっています。
うまく行ったところで本番プログラムに組み込むようにしていますが、
このようにしないと何か問題が起きた時に、その問題の原因が分かりにくいからです。

> このエラーはSqlSeverにあるデータベースに接続が失敗したのか、
> それとも接続自体は成功しているがその後の処理が失敗したのか、

この辺を理解するためには、まず(1)と(3)のみの実装、その後(2)のa)のみの実装、
両方思い通りになったことで(1)~(3)の組み込みという工程にすべきかと思います。

投稿者 社会人  (社会人) 投稿日時 2014/4/21 12:04:24
>anさん

VBを作る際に利用している参考書に前回の複数条件検索プログラムや今回のログインプログラムを作っていますが、参考書にデータベースの切断が触れていないので、他の参考書やネットなどで調べてみも青い波線(文法エラー)などでプログラムが実行出来ません。
参考書の丸写しですが、(1)と(2)のコードを作る事が出来ました。

※新規のフォームにButtonが二個、DatagridViewが一個ある状態です。

Private Sub btnGo_Click(sender As System.Object, e As System.EventArgs) Handles btnGo.Click
        Dim DS As String = "Data Source=user;Initial Catalog=データベース;Integrated Security=True"
        Dim AA As String = "SELECT パスワード FROM ユーザー情報"
        Dim DT As New DataTable
        Dim DA As New SqlDataAdapter(AA, DS)
        Try
            DA.Fill(DT)
            DataGridView1.DataSource = DT
        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        End Try

    End Sub

これで、ユーザー情報のパスワードのみ表示出来る事は確認出来ました。

説明がしずらいですが、数学や化学のように特定のプログラムコードに○○式などの名前はあるのでしょうか?
それが分かれば検索する際に「vb ○○式 SQL切断」と検索が出来て作業が進むと思ったんですが・・・
投稿者 an  (社会人) 投稿日時 2014/4/21 14:04:55
> VBを作る際に利用している参考書に前回の複数条件検索プログラムや今回のログインプログラムを作っていますが、
> 参考書にデータベースの切断が触れていないので、
> 他の参考書やネットなどで調べてみも青い波線(文法エラー)などでプログラムが実行出来ません。
> 参考書の丸写しですが、(1)と(2)のコードを作る事が出来ました。

> ※新規のフォームにButtonが二個、DatagridViewが一個ある状態です。

> Private Sub btnGo_Click(sender As System.Object, e As System.EventArgs) Handles btnGo.Click
> ~略~
> End Sub

> これで、ユーザー情報のパスワードのみ表示出来る事は確認出来ました。

これは以前の
「複数条件のプログラムを作りたい」
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=15515
で行っていた方式ですよね?
(対象テーブルが異なり、条件がない簡略した形)
一般的にデータバインドと呼ばれる方式です。
これは画面側に直接データを表示するような方式で、
今回のログインような内部的に処理するものには向いていないと思います。
(使えない事はないと思いますが、今後の理解等を考えるとこの方式で進めない方が良いと思います。)

とりあえずこれが動いているという事は接続文字列・SQLは問題がないものと思います。
こちらではSQLServerの環境がないため、動作確認できないので的確な事は言えませんが、
上記ページに記載されているサンプルを元に接続文字列・SQLのみをご自身の環境用にすれば
良いと思います。
(これは以前からそう言っています。)

単純に切断とは何かがよく分かっていないという事であれば、
上記ページのソースコードでいうところの、
Cn.Close()
が切断です。

そういった意味で前回
>> この辺を理解するためには、まず(1)と(3)のみの実装、
というのは
SqlConnection(変数名cn)の
・Openメソッド
・Closeメソッド
・ConnectionString(接続文字列)プロパティ
のみの実装という意味です。



> 説明がしずらいですが、数学や化学のように特定のプログラムコードに○○式などの名前はあるのでしょうか?
> それが分かれば検索する際に「vb ○○式 SQL切断」と検索が出来て作業が進むと思ったんですが・・・ 

方程式とかそういう話ですよね?
プログラムにはデザインパターンという考え方はありますが、
今回のようなものに当てはまるのは、自分は知りません。
なのでデザインパターンで検索してもあまり意味は無いような気がします。
(逆に下手に情報を手に入れると余計混乱する気がします。)



ここからは本題とはそれますが、以前
>上司からヒントとかを貰い、
と仰っていましたが、口頭でやりとりできる状況であれば、そちらで話を進めるべきだと思います。
ネット経由ですと質問者さんの思っている内容をすべて文字にしてくれないと伝わりませんし、
こちらの思いも伝わりにくいと思います。
例えば
>青い波線(文法エラー)などでプログラムが実行出来ません。
とだけ言われてもこれではこの掲示板を見ている人からはどのようなエラーかは特定できませんので、
回答できませんので。

投稿者 HiDE-Ada  (社会人) 投稿日時 2014/4/22 01:41:47
また一覧検索へ戻っているようですが、ログイン画面はできたのでしょうか?

一度、ここのデータベース講座第4回を読んでみてはどうでしょうか?
対象がOleDbになってますが、SQLに置き換えて読めばSQLServerに対応できます。

再確認ですが
1)起動時に表示されるのは、ログイン画面?
2)ログイン画面には、IDとPASSを入力するTextBoxと実行ボタン、キャンセルボタンだけがある。
3)実行ボタンをクリックするとログインの確認を行う。
4)ログインが成功すれば、一覧画面を表示する。(ログイン画面は非表示)
5)ID、PASSの未入力やDBに未登録の場合、MessageBoxで通知する。
5)キャンセルボタンをクリックすると、終了する。
ですか?

そのまま使えるコードを提示したいですが、はっきりした情報がないと書けないですから^^;
投稿者 社会人  (社会人) 投稿日時 2014/5/2 12:09:46

遅くなってすみません。

>HiDE-Adaさん
>データベース講座第4回

ログインについて触れていませんがデータベースの接続方法を学べるという意味でしょうか?

>確認事項
ログイン画面にはIDとPASSとメッセージを表示するTextboxが3つあります。
IDとPASSの未入力と間違っている場合はメッセージ表示専用のTextboxに表示する流れになっています。
それ以外は全部当たっています。

>anさん
>向いていないと思います。
分かりました。この方法は検索などで使うことにします。


話が大分後退しますが、
http://homepage1.nifty.com/rucio/main/dotnet/Samples/Sample033ConnectSQLServer.htm
でのwindows認証コードで

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim St As String
    Dim Cn As New System.Data.SqlClient.SqlConnection
    Dim SQL As System.Data.SqlClient.SqlCommand
    ※ Dim ServerName As String = "(local)" 'サーバー名(またはIPアドレス)
    ※ Dim DatabaseName As String = "Northwind" 'データベース

    ※ St = "Server=""(local)"";"
    St &= "integrated security=SSPI;"
    ※ St &= "initial catalog = Northwind"

    ※ Cn.ConnectionString = St

    SQL = Cn.CreateCommand

    SQL.CommandText = "SELECT FirstName FROM Employees"

    Cn.Open()

    MsgBox(SQL.ExecuteScalar)

    Cn.Close()
    SQL.Dispose()
    Cn.Dispose()

End Sub

※印は自分の環境に合わせて入力するという認識で大丈夫でしょうか?
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/5/3 16:50:13
ごめんなさい、間違えてました。
「第3回データの読み書き」
でした。

※の部分は、おっしゃるとおりに自分の環境に合わせます。

St = "Server=" & ServerName & ";"
St &= "integrated security=SSPI;"
St &= "initial catalog = " & DatabaseName

かな
投稿者 社会人  (社会人) 投稿日時 2014/5/8 10:31:26
>Hide=Adaさん

St = "Server=" & ServerName & ";"
St &= "integrated security=SSPI;"
St &= "initial catalog = " & DatabaseName

の組み合わせで自分の環境に合わせると、「SQL Server への接続を開けませんでした(error:40)」というエラーが

Cn.open()

の所で発生しましたが、

St = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"

という表記に変えると正しい結果が返ってきましたが、最初に書いた三段のコードに変更したら良いのでしょうか?

以下、現状のコードです
※テストフォームを作って、フォーム上にはbtnが一つだけあります。

Private Sub btnGo_Click(sender As System.Object, e As System.EventArgs) Handles btnGo.Click
        Dim St As String
        Dim Cn As New System.Data.SqlClient.SqlConnection
        Dim SQL As System.Data.SqlClient.SqlCommand
        Dim ServerName As String = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"
        Dim DatabaseName As String = "ユーザー情報"

        St = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"

        Cn.ConnectionString = St

        SQL = Cn.CreateCommand

        SQL.CommandText = "SELECT ID FROM ユーザー情報 WHERE パスワード = 3"

        Cn.Open()

        MsgBox(SQL.ExecuteScalar)

        Cn.Close()
        SQL.Dispose()
        Cn.Dispose()

       End Sub
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/5/8 17:07:54
Dim ServerName As String = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"

St = "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"

変数ServerNameとStに同じ値を設定していることに気づいてますか?
Stの値で接続できるなら、このままでいいと思います。
投稿者 社会人  (社会人) 投稿日時 2014/5/8 17:51:06
>HiDE-Adaさん

同じコードを二回使ってる事は気づいています。
不具合が発生するまで変更せずにこのまま行きます。

SQLServerに接続は出来ましたが、ユーザーIDとパスワードが入力されたTextBoxの情報をSQLServerに参照するコードと参照後にIDとパスワードが合っていた場合の動き(コード)が分かりません。

試しに

 SQL.CommandText = "SELECT ユーザーID FROM ユーザー情報 WHERE パスワード = '" & TextBox1.Text.Trim & "'"

を実行したら正しい結果が返ってきましたが、

'SQL.CommandText = "SELECT * "
        'SQL.CommandText += "FROM ユーザー情報"
        'SQL.CommandText += " WHERE (ユーザーID LIKE '" & TextBox1.Text.Trim & "&')"
        'SQL.CommandText += " AND (パスワード LIKE '" & TextBox2.Text.Trim & "&')"

にしてみると何も表示されないmsgboxが表示されるだけです。

お手数ですがヒントをお願いします。

※今のフォームはtextboxが二個(Nameの変更無し),btnが一個あります(NameはbtnGo)
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/5/8 18:21:43
必要のないコードは極力削除することを勧めます。
あとになって、なぜそれがあるのかわからなくなってくるからです。
少なくともコメントにはしておきましょう。

MsgBoxに何も表示されないのは、条件に該当する結果がなかったからか、
結果の最初の行の最初の列の値が空白だったからです。
http://msdn.microsoft.com/ja-jp/library/system.data.sqlclient.sqlcommand.executescalar%28v=vs.110%29.aspx
投稿者 社会人  (社会人) 投稿日時 2014/5/9 16:53:42
>HiDE-Adaさん

Dim ServerName~の箇所を削除しても影響無かったのでコピーを取った後に削除しました。

最初の行と列の値が空白というのはSQLServer上のユーザー情報のテーブルの一列一行目の場所を示してるのでしょうか?
確認しましたが、空白では無く値が入っています。

それだと、条件に該当しないのでは無いかと思い。

 SQL.CommandText = "SELECT ユーザーID FROM ユーザー情報 WHERE パスワード = '" & TextBox1.Text.Trim & "'"

 SQL.CommandText = "SELECT パスワード FROM ユーザー情報 WHERE ユーザーID = '" & TextBox2.Text.Trim & "'"

と二回に分けて実行してみたら二つとも正しい結果が返ってきました。

投稿者 HiDE-Ada  (社会人) 投稿日時 2014/5/9 17:46:14
>SQL.CommandText = "SELECT * "
>        SQL.CommandText += "FROM ユーザー情報"
>        SQL.CommandText += " WHERE (ユーザーID LIKE '" & TextBox1.Text.Trim & "&')"
>        SQL.CommandText += " AND (パスワード LIKE '" & TextBox2.Text.Trim & "&')"
>にしてみると何も表示されないmsgboxが表示されるだけです。

のwhere句はAND結合なので、ユーザーIDとパスワードの両方に一致しないとだめなわけです。
ここではLIKEを使用しているので、TextBox1やTextBox2に*や?を含めると一部一致でも条件が
なりたてば結果が返されると思います。

ExecuteScalarはテーブルではなくて、where句に一致した結果(ここ重要)の1行目1列の値をObjectで返します。
なので
SQL.CommandText = "SELECT count(ユーザID) FROM ユーザ情報" _
  & " WHERE ユーザID = '" & TextBox1.Text.Trim & "' AND パスワード = '" & TextBox2.Text.Trim & "'"

で実行すれば、ユーザーID・パスワードの両方に一致するものがあれば1、なければ0がMsgBoxに表示されると
思います。
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/5/10 02:36:18
Imports System.Data.SqlClient
Public Class Form1
  Const ConnectString As String = _
    "Data Source=user;Initial Catalog=データベースシステム;Integrated Security=True"

  Private Sub btnGo_Click(sender As System.Object, e As System.EventArgs) Handles btnGo.Click
    If TextBox1.Text.Trim = "" OrElse TextBox2.Text.Trim = "" Then
      MsgBox("IDとパスワードの両方を入力して下さい")
      Exit Sub
    End If

    If checkUser(TextBox1.Text.Trim, TextBox2.Text.Trim) Then
      Me.Hide()
      Dim frm As New Form2
      frm.ShowDialog(Me)
      Me.Show()
    Else
      MsgBox("ID、パスワードが一致しません")
    End If
  End Sub

  Private Function checkUser(id As String, pass As StringAs Boolean
    Dim result As Integer = 0
    Dim sql As String = "SELECT count(ユーザID) FROM ユーザ情報" _
            & " WHERE ユーザID='" & id & "' AND パスワード='" & pass & "'"

    Using conn As New SqlConnection(ConnectString)
      Dim cmd As New SqlCommand(sql, conn)
      Try
        conn.Open()
        result = Convert.ToInt32(cmd.ExecuteScalar())
      Catch ex As Exception
        MsgBox(ex.Message)
      End Try
    End Using

    Return result <> 0
  End Function
End Class

ExecuteScalarのサンプルに合わせたバージョンです。
投稿者 (削除されました)  () 投稿日時 2014/5/13 08:50:29
(削除されました)
投稿者 社会人  (社会人) 投稿日時 2014/5/15 09:13:28
>HiDE-Adaさん

コードをそのまま自分の環境に合わせて実行させた無事にログインする事が出来ました。
本当に有難うございます。

最後に確認したい事がいくつかあります。

・Private Function checkUser~はどのタイミングで実行されているのでしょか?(ブレークポイントをbtnGo.Clickの行で設定していてもPrivate Function checkUser~に移動しているのを確認出来ませんでした)

・result = Convert.ToInt32(cmd.ExecuteScalar())の説明をお願いします。
投稿者 HiDE-Ada  (社会人) 投稿日時 2014/5/15 17:04:55
checkUserは
    If checkUser(TextBox1.Text.Trim, TextBox2.Text.Trim) Then
で呼び出しています。

result = Convert.ToInt32(cmd.ExecuteScalar())
は以前にも書きましたが、ExecuteScalar()が結果の1行目1列をオブジェクトで返すので
それを、Int32つまりIntegerへ変換しています。

もう一つ、checkUserは“SQLインジェクション”というセキュリティ上の問題があります。
これについては、“SQLインジェクション”でネット検索してみて下さい^^;
投稿者 YuO  (社会人) 投稿日時 2014/5/15 21:18:30
HiDE-Adaさんが書かれている,SQL-Injection脆弱性の他にも,
そもそもデータベースにパスワードが平文で保存されていること自体が,通常は問題です。
正当な理由 (APOPなどのプロトコルを実装する都合上,平文パスワードが無いと実装できない場合) を除いて,
・必ずハッシュ化 (復号不可能な暗号化) を行う。この時,SHA2系のような新しいハッシュ関数を利用する
・ユーザー毎に異なるソルトを使う
・ハッシュ値はストレッチングを行う
といったことをする必要があります。
平文が必要な場合でも,復号可能な暗号化を使って上記のことを行うくらいはやった方がよいでしょう。

このあたりは,Webでのユーザー管理について調べると,情報が出てくるかと思います。
投稿者 社会人  (社会人) 投稿日時 2014/5/26 11:33:43
返事が遅れてすみません。

>HiDe-Adaさん
毎回、質問に答えて頂いて本当に有難うございます。
SQLインジェクションについても調べてみます。

>YuOさん
ユーザー情報まで暗号化する事は知りませんでした。
情報有難うごいます。