Запретить вставку повторяющихся записей
Ради обучения я создал две идентичные таблицы в 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;
Но для этого нужно быть осторожным в многопользовательских сценариях. Кто-то может вставить те же данные в небольшой промежуток времени между проверкой этого мягкого ограничения и вставкой данных.
И это трудно найти неудачи