AIと戦って、あなたの人生のリスク診断 >>

お世話になります。

VB.NET2003とSQLServer2005にて開発を行っております。

Aテーブルからデータを取得してその取得データを元にBテーブルを参照する。
と、言うのがあるのですが、
Bテーブル参照時に「この接続に関連付けられている DataReader が既に開いています。この DataReader を最初に閉じる必要があります。」の
エラーとなってしまいます。

複数SQLを発行する場合、再度接続を行わなければならないのでしょうか?
同一接続内で複数のSQLを発行することは出来ないのでしょうか?

どなたかご存知でしたらお教え願います。

以下、ソース

' 変数宣言
Dim objDBConnect As SqlConnection
Dim objDBTran As SqlTransaction
Dim objSqlCmd As SqlCommand
Dim objSqlDRA As SqlDataReader
Dim objSqlDRB As SqlDataReader

' データベース接続
objDBConnect = New SqlConnection("接続文字列")
objDBConnect.Open()

' トランザクション開始
objDBTran = objDBConnect.BeginTransaction(IsolationLevel.ReadCommitted)

' SQL発行
objSqlCmd = New SqlCommand("SELECT * FROM A_TABLE", objDBConnect)
objSqlDRA = objSqlCmd.ExecuteReader()

While objSqlDRA.Read()

objSqlCmd = New SqlCommand("SELECT * FROM B_TABLE", objDBConnect)
objSqlDRB = objSqlCmd.ExecuteReader() ←ここで、エラーとなってしまいます。

End While

このQ&Aに関連する最新のQ&A

A 回答 (5件)

#1です。


ごめんなさい。1接続に対して1つだけみたいです。

▼MSDN引用
DataReader の終了
DataReader を使い終えたら、Close メソッドを呼び出す必要があります。

Command に出力パラメータや戻り値が含まれていても、DataReader が終了するまでは使用できません。

DataReader が開いている間、Connection はその DataReader によって排他的に使用されています。元の DataReader が終了するまでは、その Connection に対してはどのコマンドも実行できません。別の DataReader を作成することもできません。

参考URL:http://msdn2.microsoft.com/ja-jp/library/haa3afy …
    • good
    • 0
この回答へのお礼

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

>1接続に対して1つだけみたいです。
という事は、DataReader では出来ないという事ですね。
DataReaderを使用するなら、DataReaderから別な入れ物にコピーして再度、DataReaderにて取得を行う。 の方法でいくしかないでしょうか?

また、別な方法がありましたら教えて頂けませんでしょうか?

お礼日時:2006/10/26 17:15

説明を読む限りselect文ないで結合させて一つのSQL文にすれば良いだけの


様に思えるのですが
    • good
    • 0

DataReaderは1つの接続に対して、1つしかopenできません。


なので、接続(SqlConnection)を2つ作るか、別な入れ物にコピーして…かのどちらかではないでしょうか。
別な入れ物にコピーする場合は、データセットを使うのがおすすめです。
    • good
    • 0

素直に、DataAdapter/DataSetは使えないのでしょうか?


手元に例がないので、うろ覚えで書きますが、
Dim conn as Connection
Dim sql as String
Dim dad1 as DataAdapter
Dim dad2 as DataAdapter
Dim dSet as DataSet

conn = new Connection("Data Source=~~~")

sql = "SELECT ~ FROM TBL_A WHERE ~~~"
DataAdapter dad1 = new DataAdapter(sql, conn)
dad1.Fill(dSet, "TBL_A")

sql = "SELECT ~ FROM TBL_B WHERE ~~~"
DataAdapter dad2 = new DataAdapter(sql, conn)
dad2.Fill(dSet, "TBL_B")

こんな感じ
    • good
    • 0

そんなことは無いと思います。



While objSqlDRA.Read()
objSqlCmd = New SqlCommand("SELECT * FROM B_TABLE",objDBConnect)
objSqlDRB = objSqlCmd.ExecuteReader() '←ここで、エラーとなってしまいます。
End While

手元にVB環境無いので勘で書きますが、
上記ループの2週目でエラーが発生していませんか?
だとすれば、1週目のループで objSqlDRB As DataReader が出来上がっているのに
そこにさらにDataReaderオブジェクトを重ねようとしたからじゃないですかね。。。
    • good
    • 1

このQ&Aに関連する人気のQ&A

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

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q一つのトランザクションでSELECTとUPDATEできますか? (ADO.NET)

いつもお世話になっております。

ADO.NETの話なのですが、トランザクションを開始したコネクションオブジェクトで
DataAdapterを使ったSELECTと、ExecuteNonQueryを使ったUPDATEを交互に繰り返し
行うことはできるでしょうか?

現状できていないので可能なのであれば共通関数の見直しが必要かと思っています。
いまはSELECTとUPDATEを別のコネクションで行っているのですが、UPDATE後に
同じテーブルの該当レコードをSELECTにいくため、デッドロックが発生しています。

Aベストアンサー

>それにしてもコネクションとトランザクションオブジェクトを別々に
>渡してやる必要性がよく理解できません。コネクションオブジェクトから
>トランザクションオブジェクトも参照できるのでは?と思うのですが・・・。

たしかに私も腑に落ちない・・・気がします
なにか別に設定が必要な理由があるのかも知れませんね
複数のトランザクションが存在する場合に指定が必要になるのかも!

私の過去のコードにはしっかり
sqlCommand.Transaction = tran
がありました(いつの間にか記述してたみたい)
すいません。#2ではまったくその事に触れていませんでした

憶測での回答になってしまいますが
トランザクションが割り当てられたコマンドが実行されたときに
自動的にBegin Tranされ
トランザクションが割り当てられていないコマンドが実行されたときに
自動的にCommit Tranが実行されてしまうのかも知れません
時間があったら実証して見たいと思います

QSQLを連続発行する時の正しい(?)書き方は?

Microsoft Visual Basic 2010 Express の質問です。

ExcelVBAや、AccessVBAで作成したプログラムを、VBに移そうと思っています。

ネットや本のサンプルを、自分のやりたいことに修正しつつ、一応、動作としては希望通りなのですが、元々VBAで簡易に作ったものだけに、本来なら注意すべきインスタンスの管理などがおざなりになっています。

動作は一応正常ですが、果たしてこれで良いのか不安でもありますので質問させていただきます。


大抵の本やサンプルには、複数のSQLを連続で発行するようなものは載っていませんが、いくつものSQLを順次発行していく処理をする時は、どのように記述するのが正しいでしょうか?

例えば、Access2010データベース、C:\test.accdb には、別のテーブルからリンクしたテーブル genpon があるとします。これをコピーしたテーブル、tb01を作る場合、

------------------------------------
Dim com As OleDb.OleDbCommand
Dim cn As OleDb.OleDbConnection = New OleDb.OleDbConnection( _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\test.accdb;")

cn.Open()

''現在のデータを削除
com = New OleDb.OleDbCommand("DROP TABLE [tb01];", cn)
com.ExecuteNonQuery()

''現在のデータを削除
com = New OleDb.OleDbCommand("SELECT * INTO [tb01] FROM [genpon];", cn)
com.ExecuteNonQuery()

------------------------------------

SQLとしては、現テーブルをDROPして、SELECT * INTO を発行すれば希望通りで、上記もその通り動きますが、NEWでインスタンス作成を繰り返しているのは、やってはいけない事ではないでしょうか?


さらに、例えばこのコードの続きとして、FOR~NEXTや、DO~LOOPで繰り返しを設け、その中でINSERT INTO を発行しながら、データを登録するような処理を加える場合、このままでは NEWをループの回数分、繰り返す事になります。

プロシージャの中で、ループなどで複数のSQLを発行する場合、記述として正しい作法がありましたら、教えてください。

Microsoft Visual Basic 2010 Express の質問です。

ExcelVBAや、AccessVBAで作成したプログラムを、VBに移そうと思っています。

ネットや本のサンプルを、自分のやりたいことに修正しつつ、一応、動作としては希望通りなのですが、元々VBAで簡易に作ったものだけに、本来なら注意すべきインスタンスの管理などがおざなりになっています。

動作は一応正常ですが、果たしてこれで良いのか不安でもありますので質問させていただきます。


大抵の本やサンプルには、複数のSQLを連続で発行するようなものは載って...続きを読む

Aベストアンサー

それぞれの最後、つまりExecuteNonQuery()の発行後、Dispose()すれば問題ありません。
が、どうせ同じインスタンスを利用するならば、2回目以降はCommandTextプロパティに設定されている
クエリを変更して発行、その後Dispose()でも良いでしょう。

また、移行ということで、元々問題ないのでしょうが、問題があるようならば
プリペアドステートメントによる発行を推奨します。(SQLインジェクション対策)
Accessはクエリキャッシュ機構はないでしょうから、パフォーマンスは変わらないでしょうけど。
http://msdn.microsoft.com/ja-jp/library/vstudio/yy6y35y8(v=vs.100).aspx

QDataGridViewで指定したセルの値を取得

こんにちは。

VB2008のDataGridViewで指定したセルの値を取得をする方法がわかりません。
どなたか教えてください。

Aベストアンサー

こんばんは.

 Dim Data As String
 Data = Me.DataGridView(0, 2).Value
 MsgBox(Data)

みたいな感じで取れないですかね???

QMAX値を条件にデータを取得するには?

SQL文で困っています。
ご教授下さい。


下記のようなデータがあった場合、それぞれの区分毎に
年月が最大(最新)のデータを取得したいです。
(実際には1レコードにその他項目があり、それらも取得します。)
<検索対象データ>
区分 年月   金額
-----------------------------
A   200412  600
A   200503  560
B   200311  600
B   200508  1000
B   200504  560
C   200508  400
C   200301  1100


<取得したいデータ>

区分 年月   金額
-----------------------------
A   200503  560
B   200508  1000
C   200508  400

よろしくお願いします。

Aベストアンサー

テーブル名をXXXとすると次のようなSQLでよいと思います。(最善の方法かどうかは自信がないですが)

select B.* from (select 区分, max(年月) as 年月 from XXX group by 区分) As A
inner join XXX as B on A.区分 = B.区分 and A.年月 = B.年月
order by B.区分

QCloseとDisposeの違い

みなさまこんばんわです。よろしくお願い申し上げます。

VB.NET 2008でコーディングしています。
CloseとDisposeの違いについて教えていただきたいのです。

これらのメソッドは、開いたファイルを閉じるときなどにも使いますが、今回お尋ねするのは、フォームを閉じるとき、しかも、自ら呼び出すとき(Me.Close() と、Me.Dispose() )のみに限ったこととしてお話しさせていただきます。

たとえば、ShowDialog() で呼び出したフォームは、そのフォーム内でMe.Close() しても、プロセスは残り、たとえば、タイマーコントロールのイベントに記述していますと、それは実行され続けます。

これを防ぐために、Me.Dispose() を使います。すると、きれいにプロセスは終了し、イベントは発生しない模様です。

そこで、「フォームを閉じる」意味のMe.Close() をすべてMe.Dispose() に変えてしまいました。確実にプロセスを破棄出来ると思ったからです。Webで調べると、違いは「再利用できる、できないの違い」という答えがありましたが、それはきっと、ファイルやオブジェクトのことで、フォームの場合は、再びShowまたはShowDialogで表示させることは可能でしたので、特に問題は感じていませんでした。

ところが、アプリケーション設定で、「最後のフォームを閉じるとき」にアプリケーションがシャットダウンする設定になってるのに、シャットダウンしてくれないことが起こりました。調べてみると、Me.Dispose() が原因。Me.Close() に変えるとうまくいきました。

わけわからなくなってきました。。。

ちなみに、その残ったフォームは、スタートアップフォームであり、別のフォームからShowまたはShowDialogメソッドで呼び出したものではありません。

ここで4つの仮説を立ててみました。

1. ShowDialogで呼び出したフォームは、Me.Dispose()、Showで呼び出した、あるいは、スタートアップフォームは、Me.Close() すれば破棄できる

2. ShowDialogで呼び出したフォームは、Me.Dispose()、スタートアップフォームは、Me.Close()、Showで呼び出したフォームは、どちらでも、破棄できる

3. 呼び出し方ではなく、別の要因が存在する

4. 併記する必要がある場合がある

Me.Close()
Me.Dispose()

または、

Me.Dispose()
Me.Close()



どれが正しいのでしょうか?どなたがご存じの方がいらっしゃいましたら、ご教授いただけませんでしょうか? どうぞよろしくお願い申し上げます。ありがとうございました。

みなさまこんばんわです。よろしくお願い申し上げます。

VB.NET 2008でコーディングしています。
CloseとDisposeの違いについて教えていただきたいのです。

これらのメソッドは、開いたファイルを閉じるときなどにも使いますが、今回お尋ねするのは、フォームを閉じるとき、しかも、自ら呼び出すとき(Me.Close() と、Me.Dispose() )のみに限ったこととしてお話しさせていただきます。

たとえば、ShowDialog() で呼び出したフォームは、そのフォーム内でMe.Close() しても、プロセスは残り、たとえば、...続きを読む

Aベストアンサー

Me.Close()
Me.Dispose()
は根本的に違うものです。

formについて、Close()メソッドはフォームの表示を終了させるメソッドです。

ほかのクラスも同様。すべてのDispose()メソッドについて、これはインスタンスの破棄を明示的に行うものです。

>再利用できる、できないの違い

Dispose()はインスタンスが破棄されるため、再びコンストラクタを用いて、インスタンスを生成しないいけません。

一方Close()はインスタンスが残っているので、それを利用することができます。

>1. ところが、アプリケーション設定で、「最後のフォームを閉じるとき」にアプリケーションがシャットダウンする設定になってるのに、シャットダウンしてくれないことが起こりました。調べてみると、Me.Dispose() が原因。
Me.Close() に変えるとうまくいきました。

通常はどちらでもうまくいきます。

>2. ShowDialogで呼び出したフォームは、Me.Dispose()、スタートアップフォームは、Me.Close()、Showで呼び出したフォームは、どちらでも、破棄できる

ShowDialogの場合は、メソッド内部で、ハンドルが破棄されているため、Close()メソッドの際にDispose()メソッドが呼び出されます。

>3. 呼び出し方ではなく、別の要因が存在する

そう思います。

>4. 併記する必要がある場合がある

インスタンスを明示的に破棄したほうがよい場合は多く存在します。
Disposeが使えるメンバはIDisposableをインターフェースとして持っているメンバです。
これらのメンバは、外部とのやり取りを行うものが多くあります。
たとえばSQLClientに含まれるようなメンバです。

外部とのコネクションを確実に破棄を保障してほしいなどという場合がありますよね、このようなときに使用します。

Using構文を使用するのとまったく同じ理由になります。
正確にはUsing構文を使用できるメンバには条件があります、IDisposableをインターフェースとして持っているメンバに限るというものです。

ほかにもガーベージコレクタによるファイナライズを伴うかどうかという違いがあります。
Disposeの場合はファイナライズが同時に行われるため、使用していたメモリ空間を開放することができます。

上記のような理由により、
Me.Close()
Me.Dispose()
は両方書いたほうがよいと思います。

蛇足ですが、
Me.Dispose()
Me.Close()
はエラーになります。
Me.Dispose()により、Me本体(インスタンス)は削除されてしまいます。
存在しないMeに対してCloseメソッドを要求することはできないためです。

Me.Close()
Me.Dispose()
は根本的に違うものです。

formについて、Close()メソッドはフォームの表示を終了させるメソッドです。

ほかのクラスも同様。すべてのDispose()メソッドについて、これはインスタンスの破棄を明示的に行うものです。

>再利用できる、できないの違い

Dispose()はインスタンスが破棄されるため、再びコンストラクタを用いて、インスタンスを生成しないいけません。

一方Close()はインスタンスが残っているので、それを利用することができます。

>1. ところが、アプリ...続きを読む

QVB.NETのコンボボックスについて

VB6からVB.NETでプログラミングを始めました。
コンボボックスのクリアの仕方や設定の仕方、また
取り出し方等を教えて下さい。

色々とヘルプも見てみたのですが、よく解りません。
宜しくお願い致します。

Aベストアンサー

クリアだけだと思ってました。
追記します。

Itemを操作します


'登録
For i = 1 To 10
  Me.ComboBox1.Items.Add(i.ToString)
Next

'取得
For i = 0 To Me.ComboBox1.Items.Count - 1
  MsgBox(Me.ComboBox1.Items(i).ToString)
Next

'完全クリア
Me.ComboBox1.Items.Clear()

部分クリア
Me.ComboBox1.Items.RemoveAt(Index値)

Q【VB】コンボボックスにデータベースから取り出した値を入れたい

VB2005です。

表題の通りですがやり方がよくわかりません。
データベースに接続し、
SQLで重複しない値を取り出すところまではできています。

SQL=SELECT DISTINCT FieldName FROM TableName

VB6の時はこんなソースでした
Do Until rs.EOF
   Combo1.AddItem.Fields("FieldName")
   rs.MoveNext
Loop

VB2005ではどう書くのでしょう?
よろしくご教授ください。

Aベストアンサー

DataReaderを使用したサンプルです
※DBMSが記述されていないので、接続文字列はアクセスの場合です
※テキスト書きなので試験していません
※DataSetを使用する方法もありますが、コンボボックスに表示する程度ならDataReaderで大丈夫でしょう
※VB2005ならば、TableAdapterという便利なクラスがあるそうです
※VisualStudio2005 まださわってません orz

  Dim dbFilePath As String = "C:\testdb.mdb"
  Dim connectionString As String = String.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}", dbFilePath)
  Dim sql As String = "SELECT DISTINCT FieldName FROM TableName"
  Dim conn As New OleDbConnection(connectionString)
  Dim query As New OleDbCommand(sql, conn)

  Try
    conn.Open()
    Dim reader As OleDbDataReader = query.ExecuteReader()
    While (reader.Read())
      Me.ComboBox1.Items.Add(reader.Item("FieldName"))
    End While
    reader.Close()
  Catch ex As Exception
    MessageBox.Show(ex.Message)
  Finally
    conn.Close()
  End Try

DataReaderを使用したサンプルです
※DBMSが記述されていないので、接続文字列はアクセスの場合です
※テキスト書きなので試験していません
※DataSetを使用する方法もありますが、コンボボックスに表示する程度ならDataReaderで大丈夫でしょう
※VB2005ならば、TableAdapterという便利なクラスがあるそうです
※VisualStudio2005 まださわってません orz

  Dim dbFilePath As String = "C:\testdb.mdb"
  Dim connectionString As String = String.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Sourc...続きを読む

QDataTableから条件を満たした行を別のDatatableへコピーしたい

VC#2005とSQLServer2005ExpressEditionでWindowsアプリケーションを作成しています。

データベースの中から1つのマスタテーブルのデータを呼び出すのにTableAdapterを使ってDataTableにデータをバインドしました。
そこから条件を満たしている行をすべて抽出して同じ型のDataTableにデータをコピーしたいのです。

ですから、DataTableは2つ用意しています。1つは上記の通りデータをバインドしていますが、もう1つは宣言しただけなのでまだ空っぽの状態です。
DataTableにはカラムが3列あり、その中の1列をグループIDとしています。
条件としてはグループIDが同じであるということです。
やりたいことは条件を満たしている行をすべて抽出して空のデータテーブルにコピーすることです。

どなたかご存知の方いらっしゃれば教えてください。
よろしくお願いします。

Aベストアンサー

C#だったんですね … さほど変わりないと思いますが

お使いのコードが提示されていないのでこちらで適当な変数をでっち上げております
現在お使いのコードを支障の無い範囲で提示しましょう

//元のデータテーブルがdtSourceとすると
// テーブル構造をコピー
DataTable dt = dtSource.Clone();
DataRow r = null;
foreach( DataRow dtRow in dtSource.Select("選択するための文字列"))
{
  r = dt.NewRow();
  for( int n = 0; n < dtRow.ItemArray.Length; n++ )
  {
    r[n] = dtRow[n];
  }
  dt.Rows.Add( r );
}
といった具合になると思います

# 前回の投稿中のstSorceはdtSourceの単なるミスです

Q日付型のフィールドに空白を入れる方法を教えてください

ASP(VBScript)でSQLサーバにINSET INTO文を使ってデータを格納しているのですが、日付の部分がNULLの時、「1900/1/1」が入ってしまいます。
そのまま、空白を入れる方法はどうやったらよろしいのでしょうか?

TABLE1の内容は
番号|内容|日付です。

INSERT INTO TABLE1 VALUES ( 1, 'あいう', '')

結果
1|あいう|1900/1/1

Aベストアンサー

あとは、プログラムの書き方次第ですね、、、


If hensu=Null Or hensu="" Then
dt = "NULL"
Else
dt = "'" & hensu & "'"
End IF

E_SQL = "INSERT INTO TABLE1 VALUES & _
"( 1,'あいう', " & dt& ")"
の様に書きます。

Qテーブル名を[]でくくらないとエラーになってしまう

テーブル名を[]でくくらないとエラーになってしまいます

sqlserver 2008 express edition を利用しているのですが

テーブル名 やカラム名に[]でくくってSQL文を実行しないと
エラーが出てしまいます
例えば

select * from [table]  の様にしないといけません
これを
select * from table で実行できるようにしたいのです
どうしたらいいのでしょうか

会社ではsqlserver2005を利用しているので
2008からは[]でくくる必要になったのでしょうか

それとも初期設定で何かしないといけないのでしょうか
設定方法を教えて下さい

sqlserver management studio2008もインストール済みです

Aベストアンサー

「table」はSQLの予約語です。そのため初期設定などで、「table」をそのままSQL文に使用することは出来ません。これは他のRDBも同様です。
SQL SERVERでは[]で括ることで、予約語をオブジェクト名に出来ますが、おすすめは出来ません。
なお、ANSI/ISOの標準規格では「"(ダブルクォーテーション)」で括ることで、同様にエラーを回避できます。SQL SERVERでも初期設定でANSI/ISOと同様に「"」で括るモードにすることは出来ますが、それでも予約語である以上何らかの対応は必要です。

> 会社ではsqlserver2005を利用しているので
> 2008からは[]でくくる必要になったのでしょうか

そんなことはないはずです。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング