0

SQL ステートメントと (Delphi の ADO)Query コンポーネントの操作や (Access 2003) データベース内のフィールド間の関係の設定について、何か基本的なことが欠けていると思います。SQL.Text="SELECT something FROM aTable." よりも複雑なものを削除、更新などしようとすると、エラー メッセージが表示されます。

たとえば、Outline と Reference というテーブル間に単純な多対多のリレーションシップを作成しました。ジャンクションまたは結合テーブルは、注:

Outline
  OutlineID (PK)
  etc.

Reference
  RefID (PK)
  etc.

Note
  NoteID (PK)
  OutlineID
  RefID
  NoteText

Access の結合に参照整合性を強制しましたが、削除または更新をカスケードするためのチェックボックスをオンにしませんでした。一方、Delphi では、私の Query.SQL.Text は

SELECT Note.NoteID, Outline.OutlineID, Ref.RefID, Note.NoteText, Ref.Citation, Outline.OutlineText
FROM (Note LEFT JOIN Outline ON Outline.OutlineID=Note.OutlineID)
LEFT JOIN Ref on Ref.RefID=Note.RefID; 

最初は、SELECT ステートメントでキーへの参照を省略していたため、結果のテーブルからレコードを削除しようとすると、「キー列情報が不足しています」というエラーが発生しました。私は理解していると思います:実行を求められる操作のためにデータベースが必要とするすべてのフィールドを選択する必要があります。何が何に結合されているのかわからない場合、結合されたフィールドを削除、更新などすることはできません。(これは正しいですか?)

では、このクエリからレコードを削除するにはどうすればよいでしょうか。つまり、(1) NoteText、Citation、および OutlineText を示すグリッドを表示し、(2) グリッドからレコードを選択し、(3) DBNavigator の [削除] ボタンをクリックするなどの操作を行い、(4) 削除したい選択したレコードと同じ NoteID と NoteText を持つ Note テーブルのレコード。

4

2 に答える 2

2

James L と Hendra はどちらも、やりたいことを実行する方法の本質を提供します。以下はその実装方法です。

procedure TForm1.ADOQuery1BeforeDelete(DataSet: TDataSet);
var
  SQL : string;
begin
  SQL := 'DELETE FROM [Note] WHERE NoteID='+
    DataSet.FieldByName('NoteID').AsString;
  ADOConnection1.Execute(SQL);
  TADOQuery(DataSet).ReQuery;
  Abort;
end;

これにより、TADOQuery.Delete が正しく機能するようになります。Abort は、レコードを削除した後に TADOQuery がレコードを削除しようとするのを防ぐために必要です。主な欠点は、TADOQuery.ReQuery がカーソル位置を保持しないことです。つまり、現在のレコードが最初のレコードになります。

アップデート:

以下は、カーソルの復元を試みます。2 回目の Requery は好きではありませんが、(最後のレコードを削除したため) 無効なブックマークを復元しようとした後に DataSet を復元する必要があるようです。これは私の限られたテストでうまくいきました。

procedure TForm1.ADOQuery1BeforeDelete(DataSet: TDataSet);
var
  SQL : string;
  bm : TBookmarkStr;
begin
  SQL := 'DELETE FROM [Note] WHERE NoteID='+
    DataSet.FieldByName('NoteID').AsString;
  bm := Dataset.BookMark;
  ADOConnection1.Execute(SQL);
  TADOQuery(DataSet).ReQuery;
  try
    Dataset.BookMark := bm;
  except
    TADOQuery(DataSet).Requery;
    DataSet.Last;
  end;
  Abort;
end;
于 2012-07-29T01:46:36.717 に答える
0

を使用していた場合TADOTable、データセットからコンポーネントを削除すると、コンポーネントはデータベース内の削除を処理しますTADOTable。ただし、TADOQuery複数のテーブルを結合するを使用しているため、データベースの削除を別の方法で処理する必要があります。

データベースグリッド内の現在のレコードを削除するレコードを作成するとTADOQuery、データセット内のその行にカーソルがスクロールされます。TADOQuery.Deleteその後、を使用して現在のレコードを削除できます。イベントのコードを作成するとTADOQuery.BeforeDelete、ローカルで削除される前にレコードからidフィールドをキャプチャでき、別のコンポーネントTADOQueryまたはTADOCommandコンポーネントを使用して、SQLを作成および実行して、データベースからレコードを削除できます。

データベースからレコードを削除するコードがBeforeDeleteイベントに含まれているため、例外が発生してデータベースレコードが削除されない場合、ローカル削除もキャンセルされ、ローカルレコードは削除されません。エラーが発生します。表示されます(例:「外部キー違反」...)。

于 2012-07-27T17:41:46.403 に答える