Копирование записей – довольно частая операция для бизнес-приложений, созданных в My Visual Database. Обычно для этого используют форму в режиме редактирования и трюк со значением свойства dbGeneralTableID у кнопки, отвечающей за сохранение данных.
Другой способ получения копии записи таблицы – это использование SQL запроса.
INSETR INTO cycle (code,type,description) SELECT code,type,description FROM cycle WHERE id=1
Code language: SQL (Structured Query Language) (sql)
В этом примере делается копия записи с ID=1 для таблицы cycle, в которой имеется три поля: code, type и description.
А можно ли скопировать запись, не зная структуры таблицы? Можно! Для этого нам понадобится временная таблица (данная технология поддерживается в СУБД SQLite и MySQL).
function DB_CopyRecord( ATableName: string; AID: integer ):integer;
// универсальная функция копирования записи
begin
// создаем временную таблицу со структурой, идентичной копируемой записи
SQLExecute('CREATE TEMPORARY TABLE tmp AS SELECT * FROM ['+ATableName+'] WHERE id = '+IntToStr(AID));
// сбрасываем значение поля ID
SQLExecute('UPDATE tmp SET id = NULL');
// вставляем запись обратно
SQLExecute('INSERT INTO ['+ATableName+'] SELECT * FROM tmp');
// получаем ID новой записи
Result := Last_Insert_ID();
// удаляем временную таблицу
SQLExecute('DROP TABLE tmp');
end;
Code language: Delphi (delphi)
На вход процедуры подаются название таблицы и идентификатор записи для копирования. На выходе – идентификатор копии.
На уровне базы данных уникальность записей в проектах My Visual Database поддерживается только для обязательного поля ID, поэтому в строке 7 выполняется команда, устанавливающая его значение в NULL. Это необходимо для того, чтобы при вставке копии (строка 9) значение поля ID установилось автоматически самой СУБД.
Пример использования процедуры, в котором у копии модифицируется поле с названием.
var
tmpIDOrder: integer;
tmpIDNewOrder: integer;
begin
...
tmpIDNewOrder := DB_CopyRecord( 'order', tmpIDOrder ); // копируем заказ
SQLExecute('UPDATE [order] SET name = (SELECT name FROM [order] WHERE id = '+IntToStr(tmpIDNewOrder)+') || " (копия)" WHERE id = '+IntToStr(tmpIDNewOrder));
Code language: JavaScript (javascript)
Примечание
Особенностью работы команды SQLQuery является блокировка базы SQLite, поэтому, если вы решили использовать процедуру DB_CopyRecord() для копирования нескольких записей, то убедитесь, что не вызываете её внутри цикла, в котором используется открытый командой SQLQuery датасет. Это требование вызвано тем, что для выполнения команды DROP TABLE требуется полный доступ к БД.
Обойти это ограничение можно, если заменить цикл while и SQLQuery на цикл for и SQLExecute. Так как для копирования вам нужны только ID записей, то можно извлечь и преобразовать в массив. Ниже приводится пример кода для копирования детализации заказа:
var
tmpID: integer;
tmpIDOrder: integer;
tmpListID: array of string;
i: integer;
tmpSQL: string;
begin
...
tmpSQL := 'SELECT GROUP_CONCAT(id) FROM orderPosition WHERE id_order = '+IntToStr(tmpIDOrder);
tmpListID := SplitString(SQLExecute(tmpSQL),',');
for i:=0 to length(tmpListID) - 1 do
begin
tmpID := DB_CopyRecord( 'orderPosition', StrToInt( tmpListID[i] ) ) );
...
end;
...
end;
Code language: Delphi (delphi)
