Microsoft Access 掲示板

リレーショナルで連鎖削除すると、#DELETEDと表示される

12 コメント
views
4 フォロー

こんばんわ、ろでますです。

たびたびの質問で恐縮なのですが、この度、
基礎情報ーID情報
という2つのテーブルでリレーショナルを組んでいます。

この際、基礎情報にはPKで「個人ID」というフィールドがあります。
そして、ID情報というテーブルにも「個人ID」というフィールドがあり、この間でリレーショナルを組んで2つのテーブルを結合しています。

そして、VBAで基礎情報で、例えば
「個人ID」が1のレコードを消すと、ID情報テーブルも連鎖削除するようにリレーショナル間で連鎖削除設定をしています。

VBAでの削除自体はDELETE構文で問題なく行えたのですが、その後、テーブルに消したはずの所に
「♯DELETED」
という情報が入ってしまっています。

Accsessを再起動するとテーブルから「#DELETED」はなくなるのですが、これは一体何なのでしょう。
解決手段はないでしょうか・・・

よろしくお願い申し上げます。

ろでます
作成: 2020/07/14 (火) 23:39:42
通報 ...
1

テーブルやフォームのデータシートビューでレコードを表示した状態で、別の場所、VBAとか削除クエリとか、、、で削除すると、削除されたレコードが「#DELETED」と表示されるのは、仕様です。

通常は、運用中にテーブルは開かないようにすべきですので、問題は、フォームでの表示の場合ですよね。
フォームでカレントレコードを削除したい場合は、DoCmd.RunCommand acCmdDeleteRecord で削除すればそのようなことにはなりません。
VBAや削除クエリから削除した場合は、その直後にそのフォームをRequeryするか、Refreshすれば「#DELETED」は消えます。

2
ろでます 2020/07/15 (水) 01:00:47 61da2@be317

早々のご回答どうもありがとうございます。
ただ、この削除フォームは「ポップアップ」フォームで行っており、リンク親フィールド、凝フィールドの設定自体がなかったことから、仕方なく(?)以下のような形で削除フォームを組んでいます。

まず、親フォームの「個人ID」コンボボックスで個人ID選択すると、親フォームの4つのテキストボックスに
氏名・郵便番号・住所・年齢
が入るようにしています。

そして、その親フォーム上に「ユーザー情報変更」ボタンがあり、これにイベントプロシージャを割り当てて、ポップアップのフォームを上げています。

そして、そのポップアップフォームのロード時に
    Me.UC_個人ID = DLookup("個人ID", "基礎情報マスタ", "個人ID=" & [CMB_個人ID])
    Me.UC_氏名 = [Forms]![ポップアップ入力]![PF_氏名]
    Me.UC_郵便番号 = [Forms]![ポップアップ入力]![PF_郵便番号]
    Me.UC_住所 = [Forms]![ポップアップ入力]![PF_住所]
    Me.UC_年齢 = [Forms]![ポップアップ入力]![PF_年齢]
    Application.SetOption "Move After Enter", 0
    End Sub

(「CMB_個人ID」は、メインフォームで入れている個人IDのコンボボックスの値をグローバル変数として代入したものです。Me.UC_氏名・・・等は、このポップアップフォームのテキストボックスのコントロール名です)

というように、メインフォームから値を代入しています。
つまり、メインフォームで
「現在選択している個人IDのユーザー情報をポップアップのサブフォームのテキストのコントロールに代入している」
ということになります。
そして、以下のような削除プロシージャ―を作りました。

Private Sub ユーザー情報削除_Click()
    Dim strSQL As String
    MsgBox "登録情報を削除します"
    strSQL = "DELETE * FROM 基礎情報マスタ where 基礎情報マスタ.個人ID=" & UC_個人ID & ";"
    DoCmd.RunSQL (strSQL)
    Me.Requery
    Forms!ポップアップ入力.Requery
    DoCmd.Close acForm, "ユーザー情報編集フォーム", acSaveNo
End Sub
(ポップアップ入力がメインフォームの名前です)

ですので、カレントレコードは1つしかないような形です(レコードセレクタでは1つしかありませんでした)。
ですので、DoCmd.RunCommand acCmdDeleteRecordを実行すると、必ず1レコード目が削除されてしました。

また、ポップアップ型のフォームだと無理なのか、メインフォームにも、ポップアップをしたサブフォームにもRequery、Refreshをかけても、♯DELETEDは消えませんでした。

また、多分根本的な間違いを犯しているんでしょうね・・・。

長々と失礼いたしました。

すいません、読んでいただいてご教授いただけましたら助かります。

3

文章では状況かよくわからないので、右カラムのファイル送信フォームから現状のフォームを送信してもらえますか。

たぶん、連結フォームの使い方が理解できていないのが原因だと思います。

4
ろでます 2020/07/15 (水) 17:27:13 61da2@be317

こんにちわ、ろでますです。
たびたびのご厚意ありがとうございます。

簡素化したファイルをアップロードさせていただきます。

フォームは最初に出てくるポップアップフォームと、「削除フォームへ」と押せるボタンから出てくるポップアップフォームだけになっています。

よろしくお願い申し上げます。

6
ろでます 2020/07/15 (水) 22:59:28 61da2@be317 >> 5

こんばんわ、ろでまです。
すいません、今気づきました。
簡素化するあまり、リレーショナル部分も切ってしまってました。

ただ状況は同じで、ポップアップサブフォームで基礎データ部分を削除すると、メインフォームのコンボボックスで#DELETEDが表示されてしまします。

7

サンプルファイルを拝見しました。
「ポップアップ入力」フォームと「ユーザー情報編集フォーム」はほぼおなじ構成ですが、2つに分ける目的はなんでしょうか。
「ポップアップ入力」はデータの閲覧用(ここで更新や削除はしない)、
更新や削除は「ユーザー情報編集フォーム」で行う、ということでしょうか。
閲覧時に不用意に、更新したり削除してしまわないようにするというのが目的でしょうか。

8
ろでます 2020/07/15 (水) 23:45:22 61da2@be317

こんばんわ、ろでますです。
簡素化せず、ごちゃごちゃな物を送付しては失礼とおもいましたので、必要な部分のみを切り出しました結果、シンプルなフォームにしてしましました。その辺のご説明ができてなくて申し訳ございません。
おっしゃる通りで、ポップアップ入力は個人データ閲覧用として、ユーザー情報編集フォームはデータ入力/編集/削除用にして、不用意な削除をできないようにしています。

簡素化するにあたり、消したところがあります。
各人のもつ、障害状況(身体障害であったり精神障害であたったり)も、メインのフォームで見れるようにしており、それらも別フォームで個別に編集できるようにしているため、分けた方が分かりやすいと判断してわけました。

もしよろしければ、そのフォームだけでも見ていただけましたら、状況を把握していただけるとおもうのですが、よろしいでしょうか・・・。(ユーザー追加などは未完成です)
先走ってすいませんが、そのファイルをアップロードさせていただきます。

9

とりあえずはそのファイルで状況は把握できます。

コンボボックスのリストに #DELETED が表示される現象の解決法は、コンボボックスを再クエリすればOKです。

Private Sub ユーザー情報削除_Click()
    Dim strSQL As String
    MsgBox "登録情報を削除します"
    'DoCmd.RunCommand acCmdDeleteRecord
    strSQL = "DELETE * FROM 基礎情報マスタ where 基礎情報マスタ.個人ID=" & UC_個人ID & ";"
    DoCmd.RunSQL (strSQL)
    DoCmd.Close acForm, "ユーザー情報編集フォーム", acSaveNo
    Forms!ポップアップ入力.Requery
    Forms!ポップアップ入力!PF_CMB_個人ID.Requery
    Forms!ポップアップ入力!PF_CMB_個人ID.Value = Null
End Sub

ただし、致命的な欠陥かあります。
「ポップアップ入力」のコンボボックスで後の方のレコードを選択してからボタンクリックで「ユーザー情報編集フォーム」を表示させると、テーブルの先頭のレコードが、コンボボックスで選択したレコードで上書きされてしまいます。

「ユーザー情報編集フォーム」を開いた直後は先頭レコードが表示されます。ところが、読み込み時イベント Form_Load() で「ポップアップ入力」のデータで上書きしてしまってます。
Form_Load()のコードは削除してください。

それから、「ポップアップ入力」のコマンドボタンクリック時のコードを下記に変更してください。

Private Sub ユーザー情報変更_Click()
    If IsNull(PF_CMB_個人ID) Then
    MsgBox "編集する人間の個人IDを入れてください"
        Exit Sub
    End If
    DoCmd.OpenForm "ユーザー情報編集フォーム", , , "個人ID=" & Me.PF_CMB_個人ID.Value
End Sub

これで、"ユーザー情報編集フォーム" のレコードは、「ポップアップ入力」と同じものになります。

10

「ポップアップ入力」は閲覧用なら、不用意な編集、削除ができないように、フォームの「レコードセット」プロパティを「スナップショット」に設定しておくといいでしょう。
あと「UC_個人ID」テキストボックスか非連結になってますが、コントロールソースを「個人ID」に設定しましょう。

"ユーザー情報編集フォーム"の「追加の許可」は「いいえ」にしておくといいでしょう。「はい」にしておくなんかの表示に新規レコードへ移動してしまう恐れがあります。
あと、「フィルターの使用」は「いいえ」に設定します。これをしておかないと、せっかく対象レコードのみ抽出されているのか、フィルターを解除されて全レコードが表示されてしまう恐れがあります。

11
ろでます 2020/07/16 (木) 08:06:10 61da2@be317 >> 10

おはようございます、ろでますです。
大変ありがとうございます、思った通りの動作ができました。
ちゃんと理解していれば、こんなスマートに書けるものなんですね。

DoCmd.OpenForm "ユーザー情報編集フォーム", , , "個人ID=" & Me.PF_CMB_個人ID.Value

で、対象のフォームのコントロールに、こういった形での引数渡しができることをはじめて知りました。

これだと、コントロールに値が入るので、他のコントロールも連動して変わってくれるという訳ですね。

また、
Forms!ポップアップ入力!PF_CMB_個人ID.Requery
Forms!ポップアップ入力!PF_CMB_個人ID.Value = Null
で、コントロール単位にReaueyできること教えていただきました。

大変良い勉強になりました、ありがとうございました。

12
hiroton 2020/07/16 (木) 11:35:26 f72e8@f966d

コントロール(コントロールソース)の理解があやふやな感じですねぇ
コントロールはコントロールソースの設定によって3種類の動作をします

1.コントロールソースにフォームのレコードソースのフィールドを指定する

指定したレコードソースのフィールドそのものにリンクされます。
現在のレコードの(指定したフィールドの)値が表示され、このコントロールを更新するとデータが書き換わります
(フィールドがクエリの計算式などの場合、編集不可だったりもします)

2.コントロールソースに計算式を指定する

計算式に従った結果が表示されます。
編集不可です。このコントロールが直接データを書き換えることはありません

3.コントロールソースに非連結を指定する

フォーム上で任意で編集ができるコントロールです。
このコントロールが直接データを書き換えることはありません
今回の例のように、表示したい個人IDを入力したり、検索用のキーワードを入力するテキストボックスを設置するときに使います。
非連結のコントロールは、ユーザーが一時的に使いたいデータを入力するためのコントロールとなります。


また、上記はコントロールの(value)に関する話で、いろいろな制御にかかわる各種プロパティは、別物です

DoCmd.OpenForm "ユーザー情報編集フォーム", , , "個人ID=" & Me.PF_CMB_個人ID.Value

これの第4引数("個人ID=" & Me.PF_CMB_個人ID.Value)はフォームのFilterプロパティに値を設定する指定です。
これ自体は何かデータを書き換えるようなことはしません。(コントロールに値を設定するようなこともありません)


サブフォームのデータを絞り込むときには

    Me!SubForm.Form.Filter = strFilter
    Me!SubForm.Form.FilterOn = True

としました。今回はフォームが別になるので、同様に考えるなら

    Forms!ユーザー情報編集フォーム.Form.Filter = strFilter
    Forms!ユーザー情報編集フォーム.Form.FilterOn = True

とすることができます。
ただし、フォームを新たに開くなら、hatenaさん提示のように同時に設定できるので

DoCmd.OpenForm "ユーザー情報編集フォーム", , , "個人ID=" & Me.PF_CMB_個人ID.Value

とできます。

同じことをしているとわかれば、個人IDを直接変更しているものではないとわかると思います。
各コントロールは、処理毎に、冒頭のコントロールのルールに従って内容を再表示します。
レコードの絞り込みの結果、現在のレコードが変更になれば、変更後のレコードの値を表示しなおします。

Excel的に言えば、見ている行が変わったというだけでデータそのものが変わったわけではありません。行が変わったので、その行の値をそれぞれ表示しなおしているだけです。