-1

为了学习,我在 SQLite 中创建了两个相同的表,并试图弄清楚如何防止将重复项从一个表插入到另一个表。我正在使用此查询来尝试在发布记录之前找出是否存在重复项。但是,它不能正常工作,因为仍然会插入重复项并且不会出现警告消息。

procedure TForm1.Button1Click(Sender: TObject);
begin
UNIQuery1.Close;
UNIQuery1.SQL.Clear;
UNIQuery1.SQL.Text:='SELECT * FROM TEMP2 WHERE DATE=:F1 AND user=:F2';
UNIQuery1.Params.ParamByName('F1').Value:=UNITable1.FieldByName('DATE').Value;
UNIQuery1.Params.ParamByName('F2').Value:=UNITable1.FieldByName('USER').Value;
UNIQuery1.Open;
if UNIQuery1.isempty then begin  
UNIQuery1.Close;
UNIQuery1.SQL.Clear;
UNIQuery1.SQL.Text:='INSERT INTO TEMP2 (DATE,USER) select DATE,USER FROM TEMP1';
UNIQuery1.ExecSQL;
UNITable2.Refresh;
end
else
ShowMessage('Record already exists !');
end;

有人可以启发我如何正确地做到这一点吗?表只有 3 个字段:ID (Autoinc)、DATE(date) 和 USER (char)。两者是相同的。所以基本上我希望程序告诉我 USER 和 DATE 已经存在于我试图发布相同记录的表中。

编辑 ; 使用 Sir Rufos 查询奇怪的事情发生了:

在此处输入图像描述

4

1 回答 1

3

SQLite has a built in function to prevent violating the constraints.

ON CONFLICT

Build a unique constraint on the fields Date and User and you can insert the new values with

insert or ignore into TEMP2 ( Date, User )
select Date, User from TEMP1

But it seems that SQLite did not get the uniqueness if one of the fields contains the NULL value.

To check if the the target table contains the values (containing NULL or not) you have to

SELECT * 
FROM TEMP2 
WHERE 
  COALESCE( "DATE", '0000-00-00 00:00:00' ) = COALESCE( :DATE, '0000-00-00 00:00:00' ) 
AND 
  COALESCE( "USER", '' ) = COALESCE( :USER, '' )

UPDATE

Your approach will not work, because you only check the current row from TEMP1 but insert all rows from it into TEMP2.

procedure TForm1.Button1Click(Sender: TObject);
begin
  // Prepare the queries

  // check duplicates query
  UNIQuery1.Close;
  UNIQuery1.SQL.Text := 'SELECT * FROM TEMP2 WHERE COALESCE( "DATE", '0000-00-00 00:00:00' ) = COALESCE( :DATE, '0000-00-00 00:00:00' ) AND COALESCE( "USER", '' ) = COALESCE( :USER, '' )';

  // insert data query
  UNIQuery2.Close;
  UNIQuery2.SQL.Text := 'INSERT INTO TEMP2 (DATE,USER) VALUES (:DATE,:USER)';

  // walk through TEMP1
  UNITable1.First;
  while not UNITable1.EOF do
  begin
    // check current row of TEMP1 for duplicates
    UNIQuery1.Params.ParamByName('DATE').Value := UNITable1.FieldByName('DATE').Value;
    UNIQuery1.Params.ParamByName('USER').Value := UNITable1.FieldByName('USER').Value;
    UNIQuery1.Open;
    // if no duplicates found
    if UNIQuery1.IsEmpty then 
    begin
      // insert the data
      UNIQuery2.Params.ParamByName('DATE').Value := UNITable1.FieldByName('DATE').Value;
      UNIQuery2.Params.ParamByName('USER').Value := UNITable1.FieldByName('USER').Value;
      UNIQuery2.ExecSQL;
      // delete current entry from TEMP1
      UNITable1.Delete;
    end
    else
      // next row from TEMP1
      UNITable1.Next;
  end;
  // refresh
  UNITable1.Refresh;
  UNITable2.Refresh;
end;

But for this you have to be careful in multi-user-scenarios. Someone can insert the same data in the small time gap between checking this soft constraint and inserting the data.

And this are hard to find failures

于 2014-03-12T06:59:47.557 回答