Запретить вставку повторяющихся записей

Ради обучения я создал две идентичные таблицы в 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(дата) и USER (char). Оба идентичные. Поэтому в основном я хочу, чтобы программа сообщила мне, что ПОЛЬЗОВАТЕЛЬ и ДАТА уже существуют в таблице, которую я пытаюсь опубликовать одинаковыми записями.

РЕДАКТИРОВАТЬ; Используя запрос сэра Руфоса, происходят странные вещи:

1 ответ

Решение

SQLite имеет встроенную функцию для предотвращения нарушения ограничений.

НА КОНФЛИКТ

Создайте уникальное ограничение на полях Date а также User и вы можете вставить новые значения с

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

Но кажется, что SQLite не получил уникальность, если одно из полей содержит NULL значение.

Проверить, содержит ли целевая таблица значения (содержащие NULL или нет) вы должны

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, '' )

ОБНОВИТЬ

Ваш подход не будет работать, потому что вы проверяете только текущую строку из TEMP1 но вставьте все строки из него в 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;

Но для этого нужно быть осторожным в многопользовательских сценариях. Кто-то может вставить те же данные в небольшой промежуток времени между проверкой этого мягкого ограничения и вставкой данных.

И это трудно найти неудачи

Другие вопросы по тегам