В данном посте соединим пример, написанный про подключение к MySQL из Delphi,
и пример про решение проблемы нескольких одновременных SQL инструкций.
вкладку Simple SQL Requests назовем DBGrid, удалим на левой панели все, что ниже кнопки “Показать таблицу”, вместо этого добавим кнопки “Добавить запись” “Редактировать запись” и “Удалить запись”… и другие кнопки…
По сути – создадим свой DBNavigator для лучшего понимания взаимодействия Delphi кода и сервера MySQL. Будем использовать тестовую БД test_db, которую создали в одном из предыдущих постов. Единственное, добавил к ней таблицу MyTable и 5 записей, для простоты… MyRecordN
Скрипт для программы-сервера MySQL для создания БД и таблиц для экспериментов….
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES'; CREATE SCHEMA IF NOT EXISTS `test_db` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ; USE `test_db` ; CREATE TABLE IF NOT EXISTS `test_db`.`Departments` ( `Primary_key` INT NOT NULL AUTO_INCREMENT , `Name` VARCHAR(45) NOT NULL , `Sort` INT NOT NULL , PRIMARY KEY (`Primary_key`) ) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `test_db`.`Employee` ( `Primary_key` INT NOT NULL AUTO_INCREMENT , `Name` VARCHAR(45) NOT NULL DEFAULT 'Default_Name' , `Family` VARCHAR(45) NOT NULL DEFAULT 'Default_Family' , `Age` INT NOT NULL DEFAULT 32 , `Salary` VARCHAR(45) NOT NULL DEFAULT '50000' , `Department_key` INT NOT NULL , PRIMARY KEY (`Primary_key`) , INDEX `FKDapartment_idx` (`Department_key` ASC) , CONSTRAINT `FKDapartment` FOREIGN KEY (`Department_key` ) REFERENCES `test_db`.`Departments` (`Primary_key` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `test_db`.`MyTable` ( `MyField` VARCHAR(45) NOT NULL ) ENGINE = InnoDB; USE `test_db` ; SET SQL_MODE=@OLD_SQL_MODE; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; START TRANSACTION; USE `test_db`; INSERT INTO `test_db`.`Departments` (`Primary_key`, `Name`, `Sort`) VALUES (1, 'Accounting', 1); INSERT INTO `test_db`.`Departments` (`Primary_key`, `Name`, `Sort`) VALUES (2, 'Marketing', 2); INSERT INTO `test_db`.`Departments` (`Primary_key`, `Name`, `Sort`) VALUES (3, 'Production', 3); INSERT INTO `test_db`.`Departments` (`Primary_key`, `Name`, `Sort`) VALUES (4, 'Sales', 4); INSERT INTO `test_db`.`Departments` (`Primary_key`, `Name`, `Sort`) VALUES (5, 'Quality_control', 5); COMMIT; START TRANSACTION; USE `test_db`; INSERT INTO `test_db`.`Employee` (`Primary_key`, `Name`, `Family`, `Age`, `Salary`, `Department_key`) VALUES (1, 'Simon', 'Kelly', 32, '50000', 1); INSERT INTO `test_db`.`Employee` (`Primary_key`, `Name`, `Family`, `Age`, `Salary`, `Department_key`) VALUES (2, 'Sally', 'Ocran', 35, '43000', 3); INSERT INTO `test_db`.`Employee` (`Primary_key`, `Name`, `Family`, `Age`, `Salary`, `Department_key`) VALUES (3, 'Ofelia', 'Oreiro', 37, '42000', 5); INSERT INTO `test_db`.`Employee` (`Primary_key`, `Name`, `Family`, `Age`, `Salary`, `Department_key`) VALUES (4, 'Ontario', 'Anapa', 40, '41000', 1); INSERT INTO `test_db`.`Employee` (`Primary_key`, `Name`, `Family`, `Age`, `Salary`, `Department_key`) VALUES (5, 'Maxim', 'Petrunin', 41, '40000', 2); COMMIT; START TRANSACTION; USE `test_db`; INSERT INTO `test_db`.`MyTable` (`MyField`) VALUES ('Record1'); INSERT INTO `test_db`.`MyTable` (`MyField`) VALUES ('Record2'); INSERT INTO `test_db`.`MyTable` (`MyField`) VALUES ('Record3'); INSERT INTO `test_db`.`MyTable` (`MyField`) VALUES ('Record4'); INSERT INTO `test_db`.`MyTable` (`MyField`) VALUES ('Record5'); COMMIT; |
Как работать с записями БД из DELPHI?
Общий принцип такой, вы обращаетесь к множеству (например, simpledataset.insert), далее, делаете что-то программно, либо ожидаете действий пользователей, далее отправляете результаты в физическую базу данных инструкциями (simpledataset.post; simpledataset.applychanges(-1);), далее обновляете множество (simpledataset.refresh)
Шаг 1 Обращаемся к множеству
1 |
Simpledataset.insert или Simpledataset.append или Simpledataset.edit или Simpledataset.delete |
Шаг 2 Подтверждаем действия, отправляем подтверждение в физическую БД
1 |
simpledataset.post; |
1 |
simpledataset.applychanges(-1); |
Шаг 3 (не обязательный) Обновляем множество
1 |
simpledataset.refresh |
Всегда закрывайте методом Post инструкции insert /append / edit / delete так как delphi от вас этого ждет)) Иначе возможны ошибки.
Как вставить запись в середину таблицы (INSERT) ?
Подробно об этом я написал здесь.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
simpledataset1.insert {Далее либо программно либо обрабатываете действия пользователей, приведу пример программной обработки} simpledataset1.FieldByName('MyField').AsString:='string'; simpledataset1.FieldByName('MyField1').AsString:='string'; simpledataset1.FieldByName('MyField2').AsString:='string'; //....Все Ваши поля подключенного simpledataset к какой-либо таблице... simpledataset1.FieldByName('MyField').AsString:='string'; //Обязательно подтверждаем.. simpledataset1.post; simpledataset1.applychanges(-1) { здесь -1 означает, что нет ограничения по ошибкам, если любое положительное число, то на этом числе при возникновении ошибок инструкция остановится...} simpledataset1.refresh; |
Но в данном абзаце скажу об основных моментах. Я экспериментировал со связкой MySQL Delphi (DBExpress)
–Факт. Если Вы выполняете insert на множестве, например на simpledataset, то при отображении в DBGrid запись вставится туда, где Вы её поставили, но как только Вы сохраните её в физическую БД, то она почти всегда добавится в конец, и если вы выполните обновление множества (например, таким способом SimpleDataSet.refresh), то и в DBGrid, она у Вас окажется в конце;
–Мое сомнение. При каких-то обстоятельствах у меня запись вставлялась иногда в начало, иногда в конец (в случае, когда ни одно поле таблицы не было помечено инструкцией Primary_key), но пока я этот вопрос исследую, сам не разобрался, почему так произошло, возможно глюк, возможно я чего-то не знаю. Чуть позже, с этой же самой таблицей при каждой вставке и сохранении в физическую БД запись вставала в конец.
–Факт. Если Вам для себя или клиента нужно отобразить вставку как вставку, то есть, показать, что вставка произошла в текущей позиции, то создайте вторую колонку Sort, и отправляйте инструкцию select*from tableneame order bySort. Подробно об этом я писал здесь.
Как добавить запись в конец (APPEND)
Подробно о добавлении записей я писал здесь. Но если вкратце, нужен “цикл”. На примере множества simpledataset…
1 2 3 4 5 6 7 8 9 10 11 12 13 |
simpledataset1.append {Далее либо программно либо обрабатываете действия пользователей, приведу пример программной обработки} simpledataset1.FieldByName('MyField').AsString:='string'; simpledataset1.FieldByName('MyField1').AsString:='string'; simpledataset1.FieldByName('MyField2').AsString:='string'; //....Все Ваши поля подключенного simpledataset к какой-либо таблице... simpledataset1.FieldByName('MyField').AsString:='string'; //Обязательно подтверждаем.. simpledataset1.post; simpledataset1.applychanges(-1) { здесь -1 означает, что нет ограничения по ошибкам, если любое положительное число, то на этом числе при возникновении ошибок инструкция остановится...} simpledataset1.refresh; |
Как отредактировать запись?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
simpledataset1.edit {Далее либо программно либо обрабатываете действия пользователей, приведу пример программной обработки} simpledataset1.FieldByName('MyField').AsString:='string'; simpledataset1.FieldByName('MyField1').AsString:='string'; simpledataset1.FieldByName('MyField2').AsString:='string'; //....Все Ваши поля подключенного simpledataset к какой-либо таблице... simpledataset1.FieldByName('MyField').AsString:='string'; //Обязательно подтверждаем.. simpledataset1.post; simpledataset1.applychanges(-1) { здесь -1 означает, что нет ограничения по ошибкам, если любое положительное число, то на этом числе при возникновении ошибок инструкция остановится...} simpledataset1.refresh; |
Как удалить запись?
1 2 3 4 5 6 |
simpledataset1.delete; //Обязательно подтверждаем.. simpledataset1.post; simpledataset1.applychanges(-1) { здесь -1 означает, что нет ограничения по ошибкам, если любое положительное число, то на этом числе при возникновении ошибок инструкция остановится...} simpledataset1.refresh; |
Как сохранить изменения в физическую БД?
Если у Вас открыт один из методов
1 2 |
Simpledataset.insert или Simpledataset.append или Simpledataset.edit или Simpledataset.delete то, чтобы сохранить изменения, нужно проделать следующие инструкции |
1 |
simpledataset.post; |
1 2 3 |
simpledataset.applychanges(-1); simpledataset1.refresh; |
Как обновить множество и данные в DBGrid?
Если компоненты соединены друг с другом и множество уже отображается в DBGrid, то очень просто
1 |
simpledataset1.refresh; |
Как перевести курсор СУБД на следующую запись?
1 |
simpledataset1.next; |
Как перевести курсор СУБД на предыдущую запись?
1 |
simpledataset1.prior; |
Как отменить последнее изменение?
1 |
simpledataset1.UndoLastChange(true); |
Как программно перейти к конкретной записи? Перевести курсор?
На одном из сайтов нашёл классную информацию по методу locate…
Текущая запись это та запись, которая имеет фокус ввода в данный момент. Для того чтобы некоторая запись стала текущей её должен выделить пользователь, также её можно выделить программно. Для того используется метод Locate:
Locate(const KeyFields: string; const KeyValues: Variant; Options:
TLocateOptions): Boolean;
Первый параметр это список полей разделяемых “точкой с запятой” либо одно поле. Второй параметр это значения, которым должны быть равны поля указанные в первом параметре если полей много то во втором параметре должен быть массив из Variant. Если указано несколько полей то переход осуществляется, только если каждое поле, указанное в первом параметре равно значению, указанному во втором параметре. Если переход прошёл успешно, то функция возвращает True. Для того чтобы получить массив из Variant можно использовать функцию VarArrayOf. Вот примеры использования метода Locate:
……
If not ClientDataSet1.Locate(‘LastName’,Edit1.text,[]) then
MessageDlg(‘ ” ‘+Edit1.text+’ ” не найдено’, mtError, [mbOK], 0);
…..
…..
ClientDataSet1.Locate(‘LastName;FirstName’, VarArrayOf( [‘Иванов’, ‘Иван’] ), []);
….
Если нужно перейти к записи, зная лишь часть строкового поля можно использовать опцию loPartialKey в третьем параметре.
ClientDataSet1.Locate(‘Address’,’Mosk’,[loPartialKey]); Часть значения не может быть где-то посередине поля она может составлять лишь несколько символов сначала.
Исходники примера статьи
Кому пригодится – 52 DBEXPRESS Insert_Copy. Там есть лишнее, это так сказать черновики. Но есть и кое-что полезное, чтобы разобраться в теме. Чтобы программа работала нужен установленный mysql с пользователем root и паролем masterkey.
В остальном – дополнительных требований нет.
Удачи в обучении программированию.