Access VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


83 / 500 ページ ←次へ | 前へ→

【11644】AccessでのExcelシート操作で教えて下さ...
質問  t_h_ben  - 10/4/29(木) 22:28 -

引用なし
パスワード
   Access VBAで教えて下さい。AccessのクエリのデータをExcelシートに貼り付けるコードを書きましたが、「RangeクラスのPasteSpecialメソッドが失敗しました。」のエラーが出ます。
Excelからのデータは一旦Temp.xlsに吐き出し、2行目のデータをコピーし、別のワークブックのシートに「値貼り付け」をしたいのです。
コピーするタイミングなどいろいろとコードを書き換えて試してみましたがうまくいきません。
ご教授宜しくお願いします。
(Windows XP/Access 2003/Excel 2003)

以下コードです。
=============================================================================

Private Sub コマンド91_Click()

On Error GoTo Err_コマンド91_Click

Dim xlApp As Object
Dim Fn As String
Dim xlFn As String
Fn = "c:\Temp\temp.xls" 'テンポラリブック
xlFn = "C:Sales.xls"

 DoCmd.OutputTo acOutputQuery,"Q_Sales_Vol",acFormatXLS,Fn,True, ""
 Set xlApp = GetObject(, "Excel.Application")
xlApp.Visible = True

With xlApp
  .ScreenUpdating = False
  .workbooks("temp.xls").Activate
  .Worksheets(1).Activate
  .Range("A2").Select
  .Range("A2:AL2").Select
  .selection.copy
  .workbooks.Open xlFn
  .Worksheets("Data").Activate
  .Range("A2").Select
  .selection.PasteSpecial Paste:=xlPasteValues '←ここでエラーが発生
  .activeworkbook.Worksheets("Sales_GR").Activate
  .range("A1").select
  .ScreenUpdating = True
  .activeworkbook.Close True
  .UserControl = True
Exit_コマンド91_Click:
On Error Resume Next
.DisplayAlerts = False
.Quit
.DisplayAlerts = True
Kill Fn
End With
Set xlApp = Nothing
Exit Sub
Err_コマンド91_Click:
MsgBox Err.Description
Resume Exit_コマンド91_Click

End Sub
=============================================================================
・ツリー全体表示

【11643】Re:テーブルのリレーションシップについて
お礼  まい  - 10/4/26(月) 14:44 -

引用なし
パスワード
   ▼超初心者 さん:

ありがとうございます

"("、")" の部分が "("、")."
となっていた為でした

そこを改善して試してみたら、うまく行きました

本当に助かりました

ありがとうございました
・ツリー全体表示

【11642】Re:テーブルのリレーションシップについて
発言  超初心者  - 10/4/26(月) 14:13 -

引用なし
パスワード
   ▼まい さん:
念の為確認です。

> 〜
> FROM [SELECT [43test].*, Null As 正規品
> 〜
> ]. AS UQ
> 〜

上から2行目と下から行目はそれぞれ、
> FROM (SELECT [43test].*, Null As 正規品
> 〜
> ) AS UQ
となしてますよね?
("["、"]."ではなく、"("、")")


一度、保存すると、"["、"]."に変わります。
変更時には、面倒ですが、"("、")"に戻して、動作確認後、保存です。
(ご存知かもしれませんが、念の為^^;;)
・ツリー全体表示

【11641】Re:テーブルのリレーションシップについて
質問  まい  - 10/4/26(月) 11:16 -

引用なし
パスワード
   ▼超初心者 さん:

ありがとうございます
早速、下記のように変えてみたところ、テストのほうはうまくいきました
しかし、実際のデータを使用して、全く同じように記述しているのに、

クエリーの構文エラーです。クエリの句が不完全です

と表示されてしまいます
>
>> WHERE テーブル2.品目3 Like Replace([テーブル1]![品目],"*","?")
> WHERE テーブル2.品目3 Like [テーブル1]![品目]
>

実際のコードを下記に記述します

SELECT UQ.品目番号, UQ.[明細テキスト行 1], UQ.数量, Last(UQ.正規品) AS 正規品
FROM [SELECT [43test].*, Null As 正規品
FROM [43test]
UNION
SELECT [43test].*, テーブル3.正規品
FROM テーブル3, [43test]
WHERE [43test].品目番号 Like テーブル3!正規品
]. AS UQ
GROUP BY UQ.品目番号, UQ.[明細テキスト行 1], UQ.数量;

ひとつ気づいたのですが、
>> WHERE テーブル2.品目3 Like Replace([テーブル1]![品目],"*","?")
> WHERE テーブル2.品目3 Like [テーブル1]![品目]

WHERE [43test].品目番号 Like テーブル3!正規品

の部分を変えると、なぜか、選択クエリからユニオンクエリになってます
これが、なんらかの原因なのでしょうか?
テストのほうでは、 ,"*","?" を取っても、選択クエリのままで、
うまくいきました。

何度もすみませんが、よろしくお願いします
・ツリー全体表示

【11640】Re:txtファイルの取込について
発言  超初心者  - 10/4/26(月) 9:43 -

引用なし
パスワード
   ▼Masato さん:
基本は「ヘルプファイル参照」です^^;;
「OPEN ステートメント」にて載ってます。

が、初めてだと「さっぱりT-T」となりそうなので、
使用例を載せてみました。

使用例を動かすと、ファイルの内容を一行ずつ
(mySTRに)取り込み、イミディエイトウィンドウに表示します。

シングルステップ[F8]での実行と、ヘルプファイルを
見比べてみると、(なんとなく?)理解できるかと思います^^;;


動きが理解できたら、mySTRの内容を INSERT INTO 〜などに加工して
実行すれば、取り込みも可能でしょう^^

定義ファイル不要なので、ファイルの内容が変わったときの変更や、
他MDBへの移行が容易である、という点から私はこの方法を使ってます^^


大した解説できませんが、参考までに^^;;
・ツリー全体表示

【11639】Re:txtファイルの取込について
質問  Masato  - 10/4/23(金) 22:47 -

引用なし
パスワード
   超初心者 さん

早速、試してみました。
テキスト変換の機能を使って、すぐできました。
ありがとうございます。

VBAのサンプルにすごく興味がありますが、
理解するまでは時間がかかります。もしコメントがつけていただければ、
ウレシイです。
・ツリー全体表示

【11638】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/23(金) 20:18 -

引用なし
パスワード
   >これなんですが
>下記コードに記載しましたが
>    'ここは、
>    'dbs Is Nothing の時 ・・・・では?
> と思いますが・・・
> のでここには排他エラーが無いような気がしますが違っていますか?
そうですね、DAOOpenDBSharedの戻り値がNothingの時はつまり誰かが排他モードでDT.DBを開いていると考えたのですが、そもそも排他では誰も開かない仕様ですね。すみません。

>>その意味では、現在作っている処理を様々なパターンでテストしてみてはいかがでしょうか。
>この辺の対応どのようにして作りこむのか良くわかりません・・・難しいです・・
>配布後、苦情の嵐とかに遭遇しそうな・・・・
とりあえず、2つのPCを使って、どなたかに協力いただいて、一方が先に更新、もう一方が後に更新などの動作チェックをしてみるだけでも安心感が増すと思います。さらにできれば負荷テストとして5〜6人で一気に更新してみるというのも有りだと思います。一応、参考まで

>で
>DAOのロック系のエラーを調べてみたのですが
>どのエラーが
>>他者のロックで開けなかった場合、ここに来るはずなので、
>となるのかわからなかったので

出典は忘れましたが、ありうるエラーを想定してそれに対処する方策を攻撃的エラートラップといいます。ですので、方策としては問題ないと思います。
・ツリー全体表示

【11637】Re:txtファイルの取込について
発言  超初心者  - 10/4/23(金) 16:39 -

引用なし
パスワード
   ▼Masato さん:

取り込み定義を作成して、
マクロの「テキスト変換」にて取り込み、
クエリにて加工していく。

恐らく、これが一番簡単?かもです^^;;
(加工のステップのクエリもマクロ化すれば一発?)


一応、VBAのサンプルを一つ
Private Sub sample()
  Dim myFileName As String
  Dim myFileNum As Integer
  Dim mySTR As String
  
  myFileName = "C:\Documents and Settings\A.txt" 'フルパス
  
  myFileNum = FreeFile
  Open myFileName For Input As #myFileNum
  Do Until EOF(myFileNum)
    Line Input #myFileNum, mySTR
    
    Debug.Print mySTR
    '〜加工して取り込む〜
  Loop
  
  Close #myFileNum
End Sub

覚えれば応用広いので使いやすいです^^

参考までに。
・ツリー全体表示

【11636】Re:テーブルのリレーションシップについて
発言  超初心者  - 10/4/23(金) 16:19 -

引用なし
パスワード
   ▼まい さん:
> など、一桁以上に一致させようとすると、うまく一致してくれません

すみません m(_~_)m
質問例から、こちらで勝手に一文字のみの判定かと解釈しておりました^^;;

> WHERE テーブル2.品目3 Like Replace([テーブル1]![品目],"*","?")
 WHERE テーブル2.品目3 Like [テーブル1]![品目]

こちらで確認してみて下さい。


> テーブル2のデータが全部で9558件あるのに、9058件と減ってしまい、
こちらについては、恐らく、同じデータが数件(差の分?)あるの
ではないでしょうか。
グループ化しているので、同じデータは1件としてしまいます。

解決策は・・・・・・分かりません m(_~_)m

主キーなどがあれば、それを元にLEFT JOINなどができるかもしれません。

あとは、最初に載せたように、
> 作業テーブルを作って、追加・更新していく方が良いかもです^^;
こんなところでしょうか。
・ツリー全体表示

【11635】txtファイルの取込について
質問  Masato  - 10/4/23(金) 15:33 -

引用なし
パスワード
   こんにちは。

 A.txt(タイトル行はない)ファイルがあるとします。
いま、取り込みするときは、手動でB.テーブルにインポートをやっています。
作業の効率がわくて、改善しようとします。
ヒントをいただけませんか?
よろしくお願いします。
・ツリー全体表示

【11634】Re:テーブルのリレーションシップについて
質問  まい  - 10/4/23(金) 13:29 -

引用なし
パスワード
   ▼超初心者 さん:

いろいろ試してみた結果、

456-* ⇒ 456-1
EEE-* ⇒ EEE-8

上記のようなケースなら、うまくいくのですが、

BBB* ⇒ BBB-56
ACB* ⇒ ACBQQ5

など、一桁以上に一致させようとすると、うまく一致してくれません

これは、どういったことが原因なんでしょうか?
何度もすみません…

どうか、よろしくお願いします
・ツリー全体表示

【11633】Re:テーブルのリレーションシップについて
質問  まい  - 10/4/23(金) 11:32 -

引用なし
パスワード
   ▼超初心者 さん:
お返事ありがとうございます

超初心者さんの記述どおり、作成してみたところ
少ないデータで動かしてみると(例でだしたデータをそのまま使用)
うまく、いくのですが、実際のデータでやってみると、
テーブル2のデータが全部で9558件あるのに、9058件と減ってしまい、
さらに、テーブル1のデータの*を含むデータは全く載ってこないという事態に
なってます

なにが、違うのか、まったく分からないんですが…
何か、原因があるとしたら、どのような事が考えられるのでしょうか?

ずーっと悪戦苦闘しております…
・ツリー全体表示

【11632】Re:MDBの分離 と レコード操作
発言  pon  - 10/4/22(木) 16:13 -

引用なし
パスワード
   続きです


>>Q2-1
>CALL UpdateUnitsInStock("Chang","33","5")
>の行を選択して、「F9」キーを押し、ブレークポイントを置きます。(茶色になる)
ありがとうございます
この辺の操作は、通常デバッグツールバーで操作できています

>うまく intMaxTries の動作を チェックすることが出来ません
今日、下記のようにして動作確認することが出来ました

PC1号機で、サーバー上のDT.MDB(NWIND.MDB)を開いておいて
PC2号機で
APP1.MDB と それをコピーしたAPP2.MDB を 両方とも開いておきます
APP1.MDB 、 APP2.MDB 各のモジュール共

   .Update ←ここにブレークポイント設定
   UpdateUnitsInStock = True

APP1.MDBで
call UpdateUnitsInStock("Chang",11,5)
を実行
APP2.MDBで
call UpdateUnitsInStock("Chang",22,5)
を実行

で、APP1.MDBを先行しブレークポイントで停止、
APP2.MDBを後攻で実行し、APP1を追い越して実行すると
エラー処理の動作を確認することが出来ました
ただ、動作の理解がまだなのでもう少し試してみたいと思います
こちらのレコードロックについても出来れば理解したいと思っています


>また、残念ながら、MDBファイルは壊れるもの、という前提で運用する方が無難なので>、バックアップ運用をすることが望ましいと思います。これも業務要件によるのです
>が、3〜5日分のバックアップを持っておけば、いざ壊れても復旧はしやすいはずです。
詳細な解説ありがとうございました
了解です

次の書込みは来週終わりになってしまうと思います
完成報告か、続けてQになってしまうかわかりませんが・・・・

今回の追加Qについて何か有りましたらコメント頂けると嬉しいです
よろしくお願い致します
・ツリー全体表示

【11631】Re:MDBの分離 と レコード操作
発言  pon  - 10/4/22(木) 16:13 -

引用なし
パスワード
   247b さん お手数かけます
わかり難い書込みのなか、回答ありがとうございます

10000文字超えのため、2度に分けました

>>DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです
詳細な説明ありがとうございます
勉強になります


Q1-1
添削頂きありがとうございます
サンプルコードが完全には理解出来ていないため
ldbが残りそうなところに
  Set rst = Nothing
  Set dbs = Nothing
を設けました

>レコードセットとデータベースを片付ける場合は、If not rst Is Nothing Then
>でオブジェクトが入っていることを確認した上で、Closeを呼び出した方が無難です。
了解です
上記
  If Not rst Is Nothing Then
    rst.Close
    Set rst = Nothing
  End If
  dbs.Close
  Set dbs = Nothing
に置き換えました

>ここに Resumeがあると、どんなエラーが発生しても実行再開してしまいますが、
>それで問題ないですか?
了解です
ありがとうございました


VBA の Recordset オブジェクトで共有データをロックする
tp://msdn.microsoft.com/ja-jp/library/cc376533.aspx

エラーのチェック
なんてありましたが、なかなか難しいです

>他者のロックで開けなかった場合、ここに来るはずなので、
>ユーザーに再度実行を促し、一旦処理終了する。
>何回かリトライする
>のいづれかの対処ができると思います。

これなんですが
下記コードに記載しましたが
    'ここは、
    'dbs Is Nothing の時 ・・・・では?
と思いますが・・・
 のでここには排他エラーが無いような気がしますが違っていますか?
(手動で開いて編集中、また、
別APP.MDBでSet DAOOpenTableExclusive = rst 中 共、どちらも同じで
   '↓ココでエラーで止まる!!
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
となってしまいました
但し、どちらも先行命令が完了すれば、後攻命令も問題なく完了します)


>排他制御も最終的には、業務要件によってどれだけシビアなものが要求されるかが決まります。
勉強になります
ありがとうございます

>その意味では、現在作っている処理を様々なパターンでテストしてみてはいかがでしょうか。
この辺の対応どのようにして作りこむのか良くわかりません・・・難しいです・・
配布後、苦情の嵐とかに遭遇しそうな・・・・

DAOのロック系のエラーを調べてみたのですが
どのエラーが
>他者のロックで開けなかった場合、ここに来るはずなので、
となるのかわからなかったので

DAOのエラー定数一覧
tp://homepage2.nifty.com/Dee/vb/tips/daoerrorlist.html
(MSサイトでは見つけられませんでした)

エラー番号    エラーメッセージ
3006    データベース <データベース名> は排他ロックされています。
3008    テーブル <テーブル名> は排他ロックされています。
3009    テーブル <テーブル名> は現在使用されているため、ロックできませんでした。
3046    他のユーザーによってロックされているため、保存できませんでした。
3158    他のユーザーによってロックされているため、レコードは保存できませんでした。
3186    マシン <マシン名> のユーザー <ユーザー名> によってロックされているため、保存できませんでした。
3187    マシン <マシン名> のユーザー <ユーザー名> によってロックされているため、読み取れませんでした。
3188    このマシンの他のセッションによってロックされているため、更新できませんでした。
3189    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって排他ロックされています。
3202    他のユーザーによってロックされているため、保存できませんでした。
3211    テーブル <テーブル名> は現在使用されているため、ロックできませんでした。
3212    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって使用されているため、ロックできませんでした。
3218    ロックされているため、更新できませんでした。
3260    マシン <マシン名> のユーザー <ユーザー名> によってロックされているため、更新できませんでした。
3261    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって排他ロックされています。
3262    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって使用されているため、ロックできませんでした。

をエラー処理の対象にしてしまえばいいかなと組み込んでしまいました・・・
邪道みたいな気もするのですが・・・・
遭遇するエラーは何とか処理の記載は出来る気もするのですが・・・
未遭遇のもの、特に今回の場合??です
というわけでこんなハズカシコードになってしまいました (~_~;)
何かアドバイス有りましたらよろしくお願い致します

修正コード

Function DAOOpenTableExclusive(strDBPath As String, _
                strRstSource As String) As DAO.Recordset
  Dim dbs As DAO.Database
  Dim rst As DAO.Recordset 
  Dim cnt As Integer '登録チャレンジ回数
 
  cnt = 0
  On Error GoTo ErrorHandler

  ' DAOOpenDBShared を呼び出して
  ' データベースを共有モードで開きます。
  Set dbs = DAOOpenDBShared(strDBPath)

  ' データベースが共有モードで開いたことを確認します。
  ' 開いた場合、指定したテーブルを排他的に開きます。
 
  If Not dbs Is Nothing Then 
   'strRstSourceが開かれていると
   '実行時エラー '3262': テーブル 'DT02_PJ_DT' は、マシン 'K000040827' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
   'で停止してしまう
   'DAOOpenTableExclusive2で、エラー処理組み込みテスト
   '↓ココでエラーで止まる!!
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
   ' レコードセットが開いたことを確認します。開いた場合、
   ' Recordset オブジェクトを返します。開かなかった場合、Nothing を返します。
   If Not rst Is Nothing Then
     Set DAOOpenTableExclusive = rst  'レコードセット ロックで開いている
    
     '追加しないと ldb.MDBが残る
     '更新処理!!
    
     If Not rst Is Nothing Then
      rst.Close
      Set rst = Nothing
     End If
     dbs.Close
     Set dbs = Nothing    
     MsgBox "登録完了"
    
   Else   
     Set DAOOpenTableExclusive = Nothing    
     'ldbが残るとやなので、下記Nothingしています!!!!!    
     If Not rst Is Nothing Then
      rst.Close
      Set rst = Nothing
     End If
     dbs.Close
     Set dbs = Nothing    
   End If
  Else
 
    '他者のロックで開けなかった場合、ここに来るはずなので、
    'ユーザーに再度実行を促し、一旦処理終了する。
    '何回かリトライする
    'のいづれかの対処ができると思います。
 
          ’ここは、
          ’dbs Is Nothing の時 ・・・・
 
 
   'Set OpenTableExclusive = Nothing
    Set DAOOpenTableExclusive = Nothing    
    
     If Not rst Is Nothing Then
      rst.Close
      Set rst = Nothing
     End If
     dbs.Close
     Set dbs = Nothing
    
  End If
 
 
Exit Function
ErrorHandler:


  'If Err.Number = 3262 Then
  Select Case Err.Number
  
    Case 3006, 3008, 3009, 3046, 3158, 3186, 3187, 3188, 3189, 3202, 3211, 3212, 3218, 3260, 3261, 3262
  
      'MsgBox "エラーです"
      'MsgBox "ターゲットテーブルは排他ONで使用中です"
      'MsgBox Err.Description 'テーブル 'DT02_PJ_DT' は、マシン 'K000040827' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
      '動作良好そう
      'ループかタイマで待機 駄目なら 時間を置いて と 思うが 動作的に 複数台のPCが ココでバッティングしたらどうなるのか自信がない
          
       '排他で開いていたら3回チャレンジして中止
       If cnt = 4 Then
      
        '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        'レコードセットとデータベースを片付ける場合は、If not rst Is Nothing Then
        'でオブジェクトが入っていることを確認した上で、Closeを呼び出した方が無難です。
        '----------------------------------------------------
      
        If Not rst Is Nothing Then
          rst.Close
          Set rst = Nothing
        End If
        dbs.Close
        Set dbs = Nothing
        
        MsgBox "ファイルが使用中か不具合が発生している可能性があります 時間を置いて登録できないときは管理者に連絡してください"
        
        
        Exit Function
        
       End If
      
       cnt = cnt + 1
      
      '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      'Resumeはここにあるべきでは?
      '----------------------------------------------------
      Resume
      
      '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      
    'Else
    Case Else
    
      MsgBox "エラー " & Err.Number & "" & Err.Description & " が発生しました"
      
       If Not rst Is Nothing Then
        rst.Close
        Set rst = Nothing
       End If
       dbs.Close
       Set dbs = Nothing
      
      Exit Function
            
  'End If
  End Select
 
  'Resume
 
End Function


Function DAOOpenDBShared(strDBPath As String) As DAO.Database
  ' このプロシージャには、Micrsoft DAO 3.6 オブジェクト ライブラリへの参照が
  ' 必要です。このプロシージャは、データベースを共有モードで開けるかどうかを
  ' 調べます。開けない場合は Nothing を返します。
  ' レコードセット ロックをインプリメントする場合、このプロシージャで
  ' データベースを共有モードで開くことができます。
  '
  ' 引数 :
  '  strDbPath : データベースへのパスです。
  '
  ' 戻り値 :
  '  共有モードで開かれているデータベースを参照する Database オブジェクトです。
  
  Dim dbs As DAO.Database

  On Error Resume Next
  ' データベースを開きます。
  Set dbs = DAO.OpenDatabase(strDBPath, False)
  
  ' エラーを確認します。
  If Err <> 0 Then
    MsgBox "Cannot open database in shared mode. " & _
      vbCr & Err.Description
    ' Nothing を返します。
    Set DAOOpenDBShared = Nothing
  Else
    ' データベースへの参照を返します。
    Set DAOOpenDBShared = dbs
  End If
End Function


今回は、取合えずテーブルロックで大丈夫そうな気がするのと
レコードレベルでの操作は荷が過ぎそうなので
テーブルロックで進めてみようと思います
・ツリー全体表示

【11630】Re:データ抽出の方法について
お礼  Masato  - 10/4/22(木) 13:50 -

引用なし
パスワード
   抽出条件を組んで、
データの抽出ができました。
本当にありがとうございました。
・ツリー全体表示

【11629】Re:テーブルのリレーションシップについて
発言  超初心者  - 10/4/22(木) 8:45 -

引用なし
パスワード
   ▼まい さん:
INNER JOIN の代わりに
WHERE 〜 Like にて抽出しています。

今回は LEFT JOIN を希望されていたようなので、
更に(品目が)空白のものをユニオンクエリにて
追加しています。
テーブル2の全レコードと、
テーブル1とテーブル2で一致したレコード(INNER JOINもどき?したもの)
それをくっつけたものがUQです。
名前は適当です(UNION QUERYから付けました^^;)

それを品目以外でグループ化し、品目の最終データ(LAST)を
抽出してます。
・ツリー全体表示

【11628】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/22(木) 4:44 -

引用なし
パスワード
   ▼pon さん:
>遅くなりました
>247b さん ありがとうございます
>
>
>>DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです。
>なんですが
>>>非連結にしましたが、
>>>結局、フォームを開くとき、
>>>コントロールのレコードソースを設定しているのでリンクテーブル有り同じことに
>>>なっているのではと思っています
>やはり、上記のような理解になってしまうのですが
>別途何か注意事項等あればコメント頂けるとうれしいです
>よろしくお願いいたします

経験的(感覚的には)リンクテーブルの方が動作は遅いような気がします。
注意事項としては、Access2000時代の話なので大丈夫だと思いますが、レコードソースプロパティを直接変更するタイプのプログラムを作って、MDBファイルがクラッシュした経験があります。事象としては、実体は数件しかデータが無いのに、数百万件データがあると認識されてしまうというものです。
こうなると、そのMDBファイルは使い物になりません。
が、稀な事象のようなので、今後のこともあるので、念のための情報として挙げておきます。

>DT.MDBが編集中で無ければ問題は無く、テーブル排他で開けましたが
>DT.MDBの競合テーブルが編集中の場合(手動で開いて編集)
>   Set rst = dbs.OpenRecordset(strRstSource, _
>     dbOpenTable, dbDenyRead + dbDenyWrite)
>でとまってしまいました
>そこで下記のようにエラー処理を追加してみました
>
>Call DAOOpenTableExclusive("\\hoge\DT.mdb","テーブル名")
>で実行
>
>Function DAOOpenTableExclusive(strDBPath As String, _
>                strRstSource As String) As DAO.Recordset
>  Dim dbs As DAO.Database
>  Dim rst As DAO.Recordset
> 
>  Dim cnt As Integer '登録チャレンジ回数 
>  cnt = 0
>
>  On Error GoTo ErrorHandler
>
>  ' DAOOpenDBShared を呼び出して
>  ' データベースを共有モードで開きます。
>  Set dbs = DAOOpenDBShared(strDBPath)
>
>  ' データベースが共有モードで開いたことを確認します。
>  ' 開いた場合、指定したテーブルを排他的に開きます。
> 
>  If Not dbs Is Nothing Then
>   '※追記1
>   'strRstSourceが開かれていると
>   '実行時エラー '3262': テーブル 'DT' は、マシン 'huga' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
>   'で停止してしまう
>   '↓ココでエラーで止まる!!
>   Set rst = dbs.OpenRecordset(strRstSource, _
>     dbOpenTable, dbDenyRead + dbDenyWrite)
>   ' レコードセットが開いたことを確認します。開いた場合、
>   ' Recordset オブジェクトを返します。開かなかった場合、Nothing を返します。
>   If Not rst Is Nothing Then
>     Set DAOOpenTableExclusive = rst  'レコードセット ロックで開いている
>     ※追記2
>     '追加しないと ldb.MDBが残る

Nothingにする前に念のためCloseしてください。

>     Set rst = Nothing
>     Set dbs = Nothing
>    
>   Else
>   
>     Set DAOOpenTableExclusive = Nothing
>     Set rst = Nothing
>     Set dbs = Nothing    
>   End If
>  Else
>   'Set OpenTableExclusive = Nothing
>    Set DAOOpenTableExclusive = Nothing
>    Set rst = Nothing
>    Set dbs = Nothing
他者のロックで開けなかった場合、ここに来るはずなので、
ユーザーに再度実行を促し、一旦処理終了する。
何回かリトライする
のいづれかの対処ができると思います。


>  End If
> 
> 
>Exit Function
>
>ErrorHandler:
>  If Err.Number = 3262 Then  
>    'MsgBox "エラーです"
>    'MsgBox "ターゲットテーブルは排他ONで使用中です"
>    'MsgBox Err.Description 'テーブル 'DT' は、マシン 'hoge' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
>    '動作良好そう
>    'ループかタイマで待機 駄目なら 時間を置いて と 思うが 動作的に 複数台のPCが ココでバッティングしたらどうなるのか自信がない
>    '排他で開いていたら3回チャレンジして中止
>     If cnt = 4 Then    
>      Set rst = Nothing
>      Set dbs = Nothing

レコードセットとデータベースを片付ける場合は、If not rst Is Nothing Then
でオブジェクトが入っていることを確認した上で、Closeを呼び出した方が無難です。

>      MsgBox "ファイルが使用中か不具合が発生している可能性があります 時間を置いて登録できないときは管理者に連絡してください"
>      Exit Function      
>     End If    
>     cnt = cnt + 1 

Resumeはここにあるべきでは?
   
>  Else  
>    MsgBox "エラー " & Err.Number & " _ " & Err.Description & " が発生しました"
>    Set rst = Nothing
>    Set dbs = Nothing
>    Exit Function          
>  End If 
>  Resume 

ここに Resumeがあると、どんなエラーが発生しても実行再開してしまいますが、それで問題ないですか?

>End Function
>
>Function DAOOpenDBShared(strDBPath As String) As DAO.Database
>  ' このプロシージャには、Micrsoft DAO 3.6 オブジェクト ライブラリへの参照が
>  ' 必要です。このプロシージャは、データベースを共有モードで開けるかどうかを
>  ' 調べます。開けない場合は Nothing を返します。
>  ' レコードセット ロックをインプリメントする場合、このプロシージャで
>  ' データベースを共有モードで開くことができます。
>  '
>  ' 引数 :
>  '  strDbPath : データベースへのパスです。
>  '
>  ' 戻り値 :
>  '  共有モードで開かれているデータベースを参照する Database オブジェクトです。
>  
>  Dim dbs As DAO.Database
>
>  On Error Resume Next
>  ' データベースを開きます。
>  Set dbs = DAO.OpenDatabase(strDBPath, False)
>  
>  ' エラーを確認します。
>  If Err <> 0 Then
>    MsgBox "Cannot open database in shared mode. " & _
>      vbCr & Err.Description
>    ' Nothing を返します。
>    Set DAOOpenDBShared = Nothing
>  Else
>    ' データベースへの参照を返します。
>    Set DAOOpenDBShared = dbs
>  End If
>End Function
>
>Q1-1
>上記で一応動作するのですが、エラー処理等自信がありません
>添削、アドバイス等頂けるとうれしいです

インラインで追記しました。

>
>Q1-2
>下記レコード レベル ロックまたはページ レベル ロックの動作が理解しきれていないので
>場合によってはこのコードでもいけそうな気がしています
>多分、更新作業も瞬時だろうし、テーブル排他のため、データの競合も発生しないので
>よさげな気がしますが、APP.MDBからのフォームの参照が切れてしまうような気がしますが
>まだ試していません
>この辺、駄目とかいけそうとかアドバイス頂けると助かります
>よろしくお願いいたします

排他制御も最終的には、業務要件によってどれだけシビアなものが要求されるかが決まります。
業務上、更新作業がほとんど重ならない程度の頻度であれば、プログラムを作り込みすぎても
重武装になるだけでメンテナンスが大変になります。
レコードのロック制御
ロックの解除制御
他人にロックされた場合の対処方法(リトライするとか、メッセージを表示するとか。処理終了するタイミングなど)
が明確になっていて、且つ実装されていれば大丈夫ではないでしょうか。
その意味では、現在作っている処理を様々なパターンでテストしてみてはいかがでしょうか。
動いているところを見ていないので、なんとも言えない部分もあるのですが。

>
>レコード レベル ロックまたはページ レベル ロック UpdateUnitsInStock
>についてですが
>
>アクセス付録のNwind.mdbをコピーして使用
>サンプルコード内でNwind.mdbフルパス、テーブル名指定
>
>Function UpdateUnitsInStock(strProduct As String, _
>              intUnitsInStock As Integer, _
>              intMaxTries As Integer) As Boolean
>は
>strProduct は Product Name 列で 商品選択
>Units In Stock は 更新DT値 
>intMaxTries は 回数 指定
>CALL UpdateUnitsInStock("Chang","33","5")
>で実行
>
>Q2-1
>うまく intMaxTries の動作を チェックすることが出来ません
>intMaxTries の デバッグ を するにはどうすればいいでしょうか

CALL UpdateUnitsInStock("Chang","33","5")
の行を選択して、「F9」キーを押し、ブレークポイントを置きます。(茶色になる)
プログラムを実行すると、このブレークポイントで処理が止まるので、あとは
ステップインして、「F8」でステップ実行で動きを確認できます。
ステップインは、ツールバーの「デバッグ」にボタンがあります。
あと、UpdateUnitsInStockの第2、3引数は数値型なので、ダブルクォーテーションは不要です。

>
>Q2-2
>別マシンでDT.MDBのProductsを開いていても
>上記を実行すると数秒、別マシンのレコードが自動更新されて再表示されます
>
>次に、別マシンでDT.MDBのProductsを開いて Units In Stock を 編集し
>上記を実行し、別レコードに移動すると
>データの競合 の ダイアログが表示され
>"レコードの保存"、"クリップボードにコピー"、または "他のユーザーによる変更を反映"
>のオプションが表示されます
>これは
>>><ADOを使ったレコード単位の排他ロックについて>
>>>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
>でも同じ動作になりした
>別マシン側ででDT.MDBのProducts で 処理選択するか
>レコード移動しなくてはいけない状況のように思われます
>
>イメージ的には、
>Function UpdateUnitsInStock
>の動作の中で、編集中です とか 待機、ループで自動処理
>できないものかと思っています
>要領を得ない質問のような気がしますが、アドバイス頂けるとうれしいです
>よろしくお願いいたします

この質問が状況が読めないのですが、レコードセットにRequeryをかけたらうまくいきませんか?


>
>Q3
>MDB破損の話はよく見かけるのですが
>今回のように、APP.MDB、DT.MDBを分離しても同じでしょうか
>壊れる、運用可 のいろんな書き込みがあってよく理解できていません
>実際にはどうなんでしょう?
>アドバイスよろしくお願いいたします
>(SQLサーバーについては、今後の目標にしています)

経験的な情報なので、確実ではないと思いますが、データベースの最適化を頻度高く行うと長持ちするように思います。このシステムの場合、特にDT.MDBの方が必要です。
また、残念ながら、MDBファイルは壊れるもの、という前提で運用する方が無難なので、バックアップ運用をすることが望ましいと思います。これも業務要件によるのですが、3〜5日分のバックアップを持っておけば、いざ壊れても復旧はしやすいはずです。
・ツリー全体表示

【11627】Re:MDBの分離 と レコード操作
質問  pon  - 10/4/21(水) 18:27 -

引用なし
パスワード
   遅くなりました
247b さん ありがとうございます


>DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです。
なんですが
>>非連結にしましたが、
>>結局、フォームを開くとき、
>>コントロールのレコードソースを設定しているのでリンクテーブル有り同じことに
>>なっているのではと思っています
やはり、上記のような理解になってしまうのですが
別途何か注意事項等あればコメント頂けるとうれしいです
よろしくお願いいたします


>要件としてはこんな感じでしょうか。
ありがとうございます
勉強になります


>なので、いわゆる排他制御が必要ということですね。
>であれば、前回挙げておられたURLのプログラムソースが参考になると思います。

>><ADOを使ったレコード単位の排他ロックについて>
>>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
ですが、いまいち・・・?で

ページ レベル ロックとレコード レベル ロック
tp://msdn.microsoft.com/ja-jp/library/cc376645.aspx
ありがとうございます

等あたり他見ているうちに
VBA の Recordset オブジェクトで共有データをロックする
tp://msdn.microsoft.com/ja-jp/library/cc376533.aspx

排他モード
共有モード
レコードセット ロック
レコード レベル ロックまたはページ レベル ロック
のサンプルコードがありました

上記について一応動作させることだけは出来たのですが下記よくわかりません

アドバイス頂けると助かります
よろしくお願いいたします


レコードセット ロック DAOOpenTableExclusive
についてですが

DT.MDBが編集中で無ければ問題は無く、テーブル排他で開けましたが
DT.MDBの競合テーブルが編集中の場合(手動で開いて編集)
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
でとまってしまいました
そこで下記のようにエラー処理を追加してみました

Call DAOOpenTableExclusive("\\hoge\DT.mdb","テーブル名")
で実行

Function DAOOpenTableExclusive(strDBPath As String, _
                strRstSource As String) As DAO.Recordset
  Dim dbs As DAO.Database
  Dim rst As DAO.Recordset
 
  Dim cnt As Integer '登録チャレンジ回数 
  cnt = 0

  On Error GoTo ErrorHandler

  ' DAOOpenDBShared を呼び出して
  ' データベースを共有モードで開きます。
  Set dbs = DAOOpenDBShared(strDBPath)

  ' データベースが共有モードで開いたことを確認します。
  ' 開いた場合、指定したテーブルを排他的に開きます。
 
  If Not dbs Is Nothing Then
   '※追記1
   'strRstSourceが開かれていると
   '実行時エラー '3262': テーブル 'DT' は、マシン 'huga' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
   'で停止してしまう
   '↓ココでエラーで止まる!!
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
   ' レコードセットが開いたことを確認します。開いた場合、
   ' Recordset オブジェクトを返します。開かなかった場合、Nothing を返します。
   If Not rst Is Nothing Then
     Set DAOOpenTableExclusive = rst  'レコードセット ロックで開いている
     ※追記2
     '追加しないと ldb.MDBが残る
     Set rst = Nothing
     Set dbs = Nothing
    
   Else
   
     Set DAOOpenTableExclusive = Nothing
     Set rst = Nothing
     Set dbs = Nothing
    
   End If
  Else
   'Set OpenTableExclusive = Nothing
    Set DAOOpenTableExclusive = Nothing
    Set rst = Nothing
    Set dbs = Nothing
  End If
 
 
Exit Function

ErrorHandler:
  If Err.Number = 3262 Then  
    'MsgBox "エラーです"
    'MsgBox "ターゲットテーブルは排他ONで使用中です"
    'MsgBox Err.Description 'テーブル 'DT' は、マシン 'hoge' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
    '動作良好そう
    'ループかタイマで待機 駄目なら 時間を置いて と 思うが 動作的に 複数台のPCが ココでバッティングしたらどうなるのか自信がない
    '排他で開いていたら3回チャレンジして中止
     If cnt = 4 Then    
      Set rst = Nothing
      Set dbs = Nothing
      MsgBox "ファイルが使用中か不具合が発生している可能性があります 時間を置いて登録できないときは管理者に連絡してください"
      Exit Function      
     End If    
     cnt = cnt + 1    
  Else  
    MsgBox "エラー " & Err.Number & " _ " & Err.Description & " が発生しました"
    Set rst = Nothing
    Set dbs = Nothing
    Exit Function          
  End If 
  Resume 
End Function

Function DAOOpenDBShared(strDBPath As String) As DAO.Database
  ' このプロシージャには、Micrsoft DAO 3.6 オブジェクト ライブラリへの参照が
  ' 必要です。このプロシージャは、データベースを共有モードで開けるかどうかを
  ' 調べます。開けない場合は Nothing を返します。
  ' レコードセット ロックをインプリメントする場合、このプロシージャで
  ' データベースを共有モードで開くことができます。
  '
  ' 引数 :
  '  strDbPath : データベースへのパスです。
  '
  ' 戻り値 :
  '  共有モードで開かれているデータベースを参照する Database オブジェクトです。
  
  Dim dbs As DAO.Database

  On Error Resume Next
  ' データベースを開きます。
  Set dbs = DAO.OpenDatabase(strDBPath, False)
  
  ' エラーを確認します。
  If Err <> 0 Then
    MsgBox "Cannot open database in shared mode. " & _
      vbCr & Err.Description
    ' Nothing を返します。
    Set DAOOpenDBShared = Nothing
  Else
    ' データベースへの参照を返します。
    Set DAOOpenDBShared = dbs
  End If
End Function

Q1-1
上記で一応動作するのですが、エラー処理等自信がありません
添削、アドバイス等頂けるとうれしいです

Q1-2
下記レコード レベル ロックまたはページ レベル ロックの動作が理解しきれていないので
場合によってはこのコードでもいけそうな気がしています
多分、更新作業も瞬時だろうし、テーブル排他のため、データの競合も発生しないので
よさげな気がしますが、APP.MDBからのフォームの参照が切れてしまうような気がしますが
まだ試していません
この辺、駄目とかいけそうとかアドバイス頂けると助かります
よろしくお願いいたします


レコード レベル ロックまたはページ レベル ロック UpdateUnitsInStock
についてですが

アクセス付録のNwind.mdbをコピーして使用
サンプルコード内でNwind.mdbフルパス、テーブル名指定

Function UpdateUnitsInStock(strProduct As String, _
              intUnitsInStock As Integer, _
              intMaxTries As Integer) As Boolean

strProduct は Product Name 列で 商品選択
Units In Stock は 更新DT値 
intMaxTries は 回数 指定
CALL UpdateUnitsInStock("Chang","33","5")
で実行

Q2-1
うまく intMaxTries の動作を チェックすることが出来ません
intMaxTries の デバッグ を するにはどうすればいいでしょうか

Q2-2
別マシンでDT.MDBのProductsを開いていても
上記を実行すると数秒、別マシンのレコードが自動更新されて再表示されます

次に、別マシンでDT.MDBのProductsを開いて Units In Stock を 編集し
上記を実行し、別レコードに移動すると
データの競合 の ダイアログが表示され
"レコードの保存"、"クリップボードにコピー"、または "他のユーザーによる変更を反映"
のオプションが表示されます
これは
>><ADOを使ったレコード単位の排他ロックについて>
>>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
でも同じ動作になりした
別マシン側ででDT.MDBのProducts で 処理選択するか
レコード移動しなくてはいけない状況のように思われます

イメージ的には、
Function UpdateUnitsInStock
の動作の中で、編集中です とか 待機、ループで自動処理
できないものかと思っています
要領を得ない質問のような気がしますが、アドバイス頂けるとうれしいです
よろしくお願いいたします

Q3
MDB破損の話はよく見かけるのですが
今回のように、APP.MDB、DT.MDBを分離しても同じでしょうか
壊れる、運用可 のいろんな書き込みがあってよく理解できていません
実際にはどうなんでしょう?
アドバイスよろしくお願いいたします
(SQLサーバーについては、今後の目標にしています)
・ツリー全体表示

【11626】Re:テーブルのリレーションシップについて
質問  まい  - 10/4/21(水) 13:52 -

引用なし
パスワード
   ▼超初心者 さん:

ありがとうございます

質問いいですか?
下記の記述で、UQという言葉がでてきてますが、
これは、今、SQLで、結合しようとしているクエリのことを指しているのでしょうか?


>SELECT UQ.品目3, UQ.区分, UQ.数量, Last(UQ.品目) AS 品目
>FROM (SELECT テーブル2.*, Null As 品目
>FROM テーブル2
>UNION
>SELECT テーブル2.*, テーブル1.品目
>FROM テーブル1, テーブル2
>WHERE テーブル2.品目3 Like Replace([テーブル1]![品目],"*","?")
>) AS UQ
>GROUP BY UQ.品目3, UQ.区分, UQ.数量;
・ツリー全体表示

【11625】Re:テーブルのリレーションシップについて
質問  まい  - 10/4/21(水) 13:49 -

引用なし
パスワード
   ▼超初心者 さん:
>
何度もすみません
もう一ついいですか?
下記の記述で、 Last(UQ.品目)となっていますが、
Lastとはどういう意味を表しているのでしょうか?
超初心者で申し訳ありません

>
>SELECT UQ.品目3, UQ.区分, UQ.数量, Last(UQ.品目) AS 品目
>FROM (SELECT テーブル2.*, Null As 品目
>FROM テーブル2
>UNION
>SELECT テーブル2.*, テーブル1.品目
>FROM テーブル1, テーブル2
>WHERE テーブル2.品目3 Like Replace([テーブル1]![品目],"*","?")
>) AS UQ
>GROUP BY UQ.品目3, UQ.区分, UQ.数量;
>
>一応、質問例のものは実現できました。
>後の作業がどのようなものかは分かりませんが、
>作業テーブルを作って、追加・更新していく方が良いかもです^^;
>
>参考までに。
・ツリー全体表示

83 / 500 ページ ←次へ | 前へ→
ページ:  ┃  記事番号:
1082653
(SS)C-BOARD v3.8 is Free