2015-02-25 3 views
3

Я получаю сообщение об ошибке:Почему при вводе записи возникает исключение «Дублирование записи»?

[FireDAC] [Phys] [MySQL] Дублировать запись '1111' для ключа 'PRIMARY'

при попытке вставить данные в базу данных. Единственными данными в базе данных является кортеж с первичным ключом «0000», поэтому я знаю, что первичный ключ не является дубликатом другого ключа. Данные вставляются в базу данных правильно, так есть ли способ остановить появление ошибки, если первичный ключ не является дубликатом?

Я использую Delphi XE7, MySQL 6.2, FDConnection и FDQuery. Мой код:

FDQuery1.SQL.Clear; 
FDQuery1.SQL.Add(
    'Insert into Customer (' + 
    'CustID,' + 
    'Forename,' + 
    'Surname,' + 
    'Address,' + 
    'PostCode' + 
    ') ' + 
    'Values (' + 
    QuotedStr(CustID) + ',' + 
    QuotedStr(Forename) + ',' + 
    QuotedStr(Surname) + ',' + 
    QuotedStr(Address) + ',' + 
    QuotedStr(Postcode) + 
    ')' 
); 
FDQuery1.ExecSQL; 
FDQuery1.Open; 
+5

Я подозреваю, что вызов 'FDQuery1.Open;' снова выполняет запрос 'INSERT'. Почему у вас там есть? Почему вы не используете параметры? И почему вы используете «Очистить» и «Добавить», если вы можете просто назначить «Текст» или, еще лучше, подготовить инструкцию и сохранить ее, изменяя только параметры и вызывая «ExecSQL»? – TLama

+2

Почему вы указываете идентификатор вместо того, чтобы полагаться на функцию автоинкремента MySQL? – GolezTrol

+0

Избавление от 'FDQuery1.Open' работало благодаря – redemon101

ответ

3

Вы выполняете ту же инструкцию SQL дважды. Сначала с ExecSQL, затем с Open. Вы должны использовать только один или другой в зависимости от того, действительно ли ваш оператор SQL возвращает любые результаты.

В вашем случае вы написали простой запрос INSERT, поэтому ExecSQL - правильный выбор. Обратите внимание: если вы используете Open с этим запросом (без ExecSQL), вы все равно получите ошибку, потому что «нет данных для открытия» (так сказать).

Чтобы подчеркнуть правило: Использовать Open, если оператор SQL возвращает данные. Вот пример, где вы бы Open, даже если ваш оператор вставляет строку.

LQuery.SQL.Text := 
    'INSERT INTO Customer (CustId, CustomerName)'#13#10 + 
    'VALUES ('+QuotedStr(ACustId)+','#13#10 + 
       QuotedStr(ACustomerName)+');'#13#10 + 
    'SELECT CustId, CustomerName, DateAdded'#13#10 + 
    'WHERE CustId = '+QuotedStr(ACustId) 
LQuery.Open; 

Как показано на рисунке, вы можете сразу же вернуть новую строку после вставки, если база данных присваивает любые значения (например, значения по умолчанию, авто-ключей, rowversion). И если это так, то вы должны использовать Open.

SIDE ПРИМЕЧАНИЕ: Я придерживался динамического запроса в соответствии с вашим вопросом. Однако, как правило, рекомендуется использовать параметризованный запрос или даже хранимую процедуру.

Смежные вопросы