質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.88%

実行時エラー(オブジェクトが開いている場合は操作は許可されません)になる

解決済

回答 1

投稿 編集

  • 評価 1
  • クリップ 1
  • VIEW 27K+

score 8

 前提・実現したいこと

Access VBA からSQL Serverの[M_取引先マスタ]にテーブルロックを掛けて、フォームに入力があった内容を新規追加したく思っています。

 発生している問題・エラーメッセージ

下記ロジックを実行すると、2つ目のSQL文実行時(M_取引先マスタのロックSQL)に
【実行時エラー '3705' オブジェクトが開いている場合は、操作は許可されません。】
とエラーになります。

SELECT COUNTのSQL文をコメントアウトすると、INSERT文の行で同エラーになります。

別ロジックで[DELETE]-->[INSERT]している部分では問題無く動作しているため、コピペするかたちで作ったのですが、SQL文実行の都度クローズしなくてはいけないのでしょうか?

 該当のソースコード

Public CN_SQL As New ADODB.Connection
Public RS_SQL As New ADODB.Recordset
' -----------------------------------------------------------------------------
' Connectionオブジェクトを生成
' -----------------------------------------------------------------------------
Public Sub DB_Connect()

Dim ConnectionString As String

Dim sDBSever As String
Dim sDBName As String
Dim sLoginID As String
Dim sPassWD As String

sDBSever = DLookup("[データ]", "M_システム", "[ID] = 'SvName'") ' SQL Serverが稼働しているサーバー名
sDBName = DLookup("[データ]", "M_システム", "[ID] = 'DbName'")  ' SQL ServerのDB名
sLoginID = DLookup("[データ]", "M_システム", "[ID] = 'Login'")  ' sa
sPassWD = DLookup("[データ]", "M_システム", "[ID] = 'Pass'")' saのパスワード

' 接続文字列
ConnectionString = "Provider=SQLOLEDB;Data Source=" & sDBSever & _
   ";Initial Catalog=" & sDBName & _
   ";Connect Timeout=15" & _
   ";user id=" & sLoginID & _
   ";password=" & sPassWD

' 接続
CN_SQL.Open ConnectionString

End Sub

' -----------------------------------------------------------------------------
' データベースへの接続を解除する
' -----------------------------------------------------------------------------
Public Sub DB_DISCONNECT()

CN_SQL.Close
Set CN_SQL = Nothing

End Sub

' -----------------------------------------------------------------------------
' 引数のSQL文を実行し、ADODB.Recordsetを返す
' -----------------------------------------------------------------------------
Public Function DB_EXECUTE(s_SQL As String, CursorType, LockType, b_FLG As Boolean) As ADODB.Recordset

b_FLG = True

' タイムアウト設定 (15分)
CN_SQL.CommandTimeout = 60 * 15

' 処理された行数を示すメッセージが結果セットの一部として返されないようにする
CN_SQL.execute ("SET NOCOUNT ON")

' 警告メッセージが結果セットの一部として返されないようにする
CN_SQL.execute ("SET ANSI_WARNINGS OFF")

' オーバーフローおよび0除算時にはNULLを返す
CN_SQL.execute ("SET ARITHABORT OFF")


RS_SQL.CursorType = CursorType
RS_SQL.LockType = LockType

RS_SQL.Open s_SQL, CN_SQL
'RS_SQL.Open s_SQL, CN_SQL, CursorType, LockType

Do
' レコードの操作ができるオブジェクト若しくは次のRecordSetがとれず、コネクションが空になった場合終了
If RS_SQL.State = adStateOpen Or RS_SQL.ActiveConnection Is Nothing Then
Exit Do
End If
Set RS_SQL = RS_SQL.NextRecordset()
Loop

Set DB_EXECUTE = RS_SQL


' 設定OFF
CN_SQL.execute ("SET NOCOUNT OFF")
CN_SQL.execute ("SET ANSI_WARNINGS ON")
CN_SQL.execute ("SET ARITHABORT ON")

End Function

' -----------------------------------------------------------------------------
' トランザクションを開始する
' -----------------------------------------------------------------------------
Public Sub BeginTransaction()

CN_SQL.BeginTrans

End Sub

' -----------------------------------------------------------------------------
' トランザクションをコミットする
' -----------------------------------------------------------------------------
Public Sub CommitTransaction()

CN_SQL.CommitTrans

End Sub

' -----------------------------------------------------------------------------
' トランザクションをロールバックする
' -----------------------------------------------------------------------------
Public Sub RollbackTransaction()

CN_SQL.RollbackTrans

End Sub

' -----------------------------------------------------------------------------
' F_取引先登録のコード
' -----------------------------------------------------------------------------
'DB接続
Call DB_CONNECT

'SQL文生成
s_SQL = ""
s_SQL = "SELECT COUNT(*) AS REC_CNT "
s_SQL = s_SQL & "FROM M_取引先マスタ "
s_SQL = s_SQL & "WHERE 取引先CD LIKE '201804%';"

i_Seq = REC_CNT + 1

'SQL文実行
RS_SQL.Open s_SQL, CN_SQL, adOpenStatic, adLockReadOnly

'トランザクション開始
Call BEGINTRANSACTION

'SQL文生成
s_SQL = ""
s_SQL = "SELECT * FROM M_取引先マスタ WITH (TABLOCK, HOLDLOCK);"

'SQL文実行
'RS_SQL.Open s_SQL, CN_SQL, adOpenKeyset, adLockPessimistic

s_SQL = ""
s_SQL = "INSERT INTO M_取引先マスタ (取引先CD, 取引先名, 取引先住所, 更新日時) "
s_SQL = s_SQL & "VALUES ( "
s_SQL = s_SQL & "'" & s_SysDate & String(3 - Len(CStr(i_Seq)), "0") & CStr(i_Seq) & "', "
s_SQL = s_SQL & "N'" & Forms!F_取引先登録.txt_取引先名.Value & "', "
s_SQL = s_SQL & "N'" & Forms!F_取引先登録.txt_取引先住所.Value & "', "
s_SQL = s_SQL & "'" & Format(Now(), "yyyy/mm/dd hh:mm:ss") & "' "
s_SQL = s_SQL & ");"

'SQL文実行
RS_SQL.Open s_SQL, CN_SQL, adOpenKeyset, adLockPessimistic

'SQL文コミット
Call COMMITTRANSACTION

'接続を閉じる
Call DB_DISCONNECT



' -----------------------------------------------------------------------------
' 以下は[DELETE]-->[INSERT]しているロジックです
' -----------------------------------------------------------------------------

'----- DB接続 -----
Call DB_Connect

'----- トランザクション開始 -----
Call BeginTransaction

'該当データをDELETE --> INSERT
s_SQL = "DELETE FROM T_案件テーブル WHERE ID = '" & KEY & "';"

'SQL文実行
RS_SQL.Open s_SQL, CN_SQL, adOpenKeyset, adLockPessimistic

s_SQL = "INSERT INTO T_案件テーブル (ID, FLD1, FLD2, FLD3) "
s_SQL = s_SQL & "VALUES ( , , , );"

'SQL文実行
RS_SQL.Open s_SQL, CN_SQL, adOpenKeyset, adLockPessimistic

'----- DBコミット -----
Call CommitTransaction

'----- 接続を閉じる -----
Call DB_DISCONNECT

 試したこと

 補足情報(FW/ツールのバージョンなど)

Access2010
SQL Server2014

  • クリップを取り消します

  • 質問の評価を上げたことを取り消します

  • 質問の評価を下げたことを取り消します

質問への追記・修正、ベストアンサー選択の依頼

回答 1

checkベストアンサー

0

RS_SQL.Openで毎回セッションを開いているんじゃないですか?
別セッションなら当然排他されますので。

追記

SELECT COUNTのSQL文をコメントアウトすると、INSERT文の行で同エラーになります。

insert って openじゃなくて、executeじゃなかった?
まあ、本題とは関係ないですけど。

追加されたコードを見るにセッションは引き継いでいるように見えますね。

Call BEGINTRANSACTION


の前でCOMMITするとどうなります?

やっぱり、openでの排他モードが関係しているような気がします。
selectでテーブル単位の排他を行っていますけど、openは基本カーソルなのでレコード単位までしかありません。
executeに変えてみてはどうでしょうか。

投稿

編集

sazi

SQL総合1位

score 21976

  • gigatail

    gigatail

    2018/04/19 17:24

    実は16日の午後から行き詰っております。
    Access <--> SQL Server というのは今回が初めてな上、社内は「データベースって何?」って感じなのでWEBからの寄せ集めで奮闘しています。
  • sazi

    sazi

    2018/04/19 17:53

    方法としては、
    1.取り敢えず排他は後回し
    2.DAOの排他に揃える
    3.with()とexecutの組合せ
    3は推測の域を出ないですが。
  • gigatail

    gigatail

    2018/04/23 11:29

    SQL文実行後に
    RS_SQL.Close
    を追記することでエラー表示なく、動作することができました。

    お忙しい中、ご教授いただきましてありがとうございます。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.88%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る