В базе данных можно создавать таблицы, добавлять в них строки с данными, удалять, редактировать их и т.д. Все эти действия выполняются через SQL-запросы к БД. Например, чтобы добавить новую строку в таблицу "my_table" с двумя целочисленными столбцами, нужно выполнить соответствующий SQL-запрос:
INSERT INTO `my_table` (col1, col2) VALUES (11, 65);
Чтобы получить содержимое таблицы "my_table", нужно выполнить SQL-запрос на выборку:
SELECT * FROM `my_table`;
Таким образом можно составить любой SQL-запрос, который будет выполнять поставленную задачу.
Важно! Обработать ошибки в SQL-запросах можно в скрипе "Ошибка SQL-запроса", например выдать ошибку в компонент "Текст". Также, для отладки скриптов работы с БД можно активировать опцию "Лог пользовательских SQL-запросов", тогда все пользовательские SQL-запросы будут записываться в лог-файл сервера. Данную опцию можно использовать только для отладки проекта, иначе она будет создавать лишнюю нагрузку на сервер скады.
Рекомендуем предварительно убедиться в том, что запрос не содержит ошибок. Например, чтобы составить и проверить SQL-запрос для MySQL, можно использовать MySQLWorkbench.
Когда SQL-запрос подготовлен и проверен, можно вызвать его из скрипта Simple-Scada. Для выполнения пользовательских SQL-запросов в Simple-Scada используется процедура RunSQL - в нее нужно передать код SQL-запроса и скада автоматически отправит этот запрос на выполнение. Допустим у нас имеется следующий SQL-запрос:
INSERT INTO `my_table` (col1, col2) VALUES (11, 65);
Требуется выполнить его, когда пользователь нажмет на кнопку. Для этого нужно выделить кнопку и на событие OnClick написать скрипт со следующим кодом:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES (11, 65);';
{ Отправляем запрос на выполнение c тегом = 0}
RunSQL(aQuery, nil, 0);
end.
Сначала мы записали текст SQL-запроса в строковую переменную aQuery, а затем вызвали процедуру RunSQL с этой строковой переменной. Далее, скада автоматически отправит наш запрос в БД. Если запрос выполнится успешно (без ошибок), то скада вызовет все скрипты с типом события "Выполнен SQL-запрос". Если при выполнении запроса что-то пойдет не так (например, в запросе имеется ошибка), то скада вызовет скрипты с типом события "Ошибка SQL-запроса".
Примеры скриптов
Порядок выполнения запросов
Все запросы к БД выполняются асинхронно. БД выполняет каждый запрос в отдельном потоке, т.е. если отправить в БД несколько запросов подряд, то они будут выполняться одновременно в разных потоках и то, какой запрос выполнится быстрее зависит от множества факторов, например нагрузки на процессор, нагрузки на саму БД, количества других запросов выполняющихся в данный момент и т.д. Поэтому, если обязательно требуется выполнить запросы последовательно, то нужно отправить в БД первый запрос, пометив его уникальным тегом. Затем в скрипте "Выполнен SQL-запрос" необходимо проверить, что выполнился запрос помеченный нужным тегом(if DataSet.Tag = ?? then), после чего можно отправить в БД второй запрос.
|
Одинарные кавычки в SQL-запросах
Пусть мы хотим выполнить такой SQL-запрос: "INSERT INTO `my_table` (col1, col2) VALUES ('привет', 'мир');". В этом запросе есть одинарные кавычки, в них мы передаём строковые константы ('привет' и 'мир'). Теперь, если мы подставим этот запрос в процедуру RunSQL, то получим ошибку компилятора, например:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES ('привет', 'мир');'; // ошибка синтаксиса!
{ Отправляем запрос на выполнение c тегом = 0}
RunSQL(aQuery, nil, 0);
end.
Дело в том, что SQL-запросы передаются в RunSQL в виде строки, а строки должны быть заключены в одинарные кавычки. Наши одинарные кавычки внутри SQL-запроса мешают компилятору правильно воспринимать строку (это видно даже по подсветке синтаксиса в примере выше). Чтобы решить проблему, нужно продублировать одинарные кавычки в SQL-запросе, вот так:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES (''привет'', ''мир'');';
{ Отправляем запрос на выполнение c тегом = 0}
RunSQL(aQuery, nil, 0);
end.
Теперь компилятор правильно воспринимает весь запрос как единую строку.
Есть ещё один вариант для решения проблемы с одинарными кавычками. Можно использовать функцию QuotedStr, которая добавляет одинарные кавычки по краям строки. Например:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES (' + QuotedStr('привет') + ', ' + QuotedStr('мир') + ');';
{ Отправляем запрос на выполнение c тегом = 0}
RunSQL(aQuery, nil, 0);
end.
|
Длинные SQL-запросы в коде
Пусть у нас есть длинный SQL-запрос: "INSERT INTO `my_table` (col1, col2, col3, col4, col5, col6) VALUES (11, 65, 25.15, 'текст1', 'текст2', 'текст3');". Если вписать его одной строкой, то на экране может просто не хватить места по ширине из-за чего придётся пользоваться горизонтальным скроллом. Правильнее будет разбить текст запроса на три строки, каждую строку заключить в одинарные кавычки и сложить их знаком "+". Вот так:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` ' +
'(col1, col2, col3, col4, col5, col6) VALUES ' +
'(11, 65, 25.15, ''текст1'', ''текст2'', ''текст3'');';
{ Отправляем запрос на выполнение c тегом = 0}
RunSQL(aQuery, nil, 0);
end.
Разбиение на строки полезно, так как улучшает читаемость кода.
|
Как понять что запрос выполнился
Пусть в проекте есть кнопка, по нажатию на которую в таблице "my_table" создаётся новая строка. Т.е. на событие OnClick написан такой код:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES (11, 65);';
{ Отправляем запрос на выполнение c тегом = 0}
RunSQL(aQuery, nil, 0);
end.
Теперь мы добавили на мнемосхему компонент текст с именем "Text1" и хотим, чтобы после выполнения нашего SQL-запроса текст изменился на "Мой запрос выполнен!". Тогда мы должны, во-первых, при вызове RunSQL пометить наш запрос каким-то уникальным тегом, который больше никогда нами в RunSQL не использовался, например 55:
var
aQuery: string;
begin
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES (11, 65);';
{ Отправляем запрос на выполнение c тегом = 55 }
RunSQL(aQuery, nil, 55);
end.
Во-вторых, необходимо создать в меню скриптов новый скрипт с типом события "Выполнен SQL-запрос". Такой скрипт будет вызываться скада-системой каждый раз, когда выполнился любой пользовательский SQL-запрос. Также, этот скрипт будет содержать параметр "DataSet" - результат выполнения запроса. У параметра DataSet имеется свойство Tag. Это и есть тот самый тег, который мы назначили при выполнении RunSQL. Таким образом, по значению тега мы можем узнать в скрипте какой именно из наших SQL-запросов выполнился. Например:
begin
if DataSet.Tag = 55 then
Text1.Text := 'Запрос выполнен!';
end.
|
Блокировка кнопки на время выполнения запроса
Допустим имеется кнопка, по нажатию на которую выполняется запрос к БД. Требуется блокировать кнопку на время выполнения запроса для предотвращения повторных нажатий. Для решения этой задачи на событие OnClick кнопки нужно написать код запроса к БД, а также пометить запрос уникальным тегом, который ранее не использовался в RunSQL, например 77:
var
aQuery: string;
begin
{ блокируем кнопку, чтобы ее нельзя было нажать повторно }
Button1.Enabled := False;
{ Формируем запрос к БД }
aQuery := 'INSERT INTO `my_table` (col1, col2) VALUES (11, 65);';
{ Отправляем запрос на выполнение c тегом = 77 }
RunSQL(aQuery, nil, 77);
end.
Далее, создадим новый скрипт с типом события "Выполнен SQL-запрос" и следующим кодом:
begin
if DataSet.Tag = 77 then // если запрос помеченный тегом 77 выполнен, то
Button1.Enabled := True; // разблокируем кнопку
end.
|
Метод RunSQL компонента "Таблица"
У компонента "Таблица" есть свой внутренний метод RunSQL, который удобно использовать для того чтобы отобразить результат выполнения SQL-запроса в таблице на мнемосхеме. Например можно создать на мнемосхеме таблицу с именем "Table1", разместить рядом кнопку "Считать" и на событие OnClick кнопки написать такой код:
var
aQuery: string;
begin
{ формируем запрос к БД на выборку всех данных из таблицы `my_table` }
aQuery := 'SELECT * FROM `my_table`';
{ выполнить запрос и заполнить таблицу результатом выполнения }
Table1.RunSQL(aQuery, tsAll);
end.
Теперь при нажатии на кнопку "Считать" скада выполнит SQL-запрос, а после выполнения автоматически отобразит результат в таблице Table1. Если запрос выполнится с ошибкой, то текст ошибки отобразится в таблице. Другие примеры для метода RunSQL таблицы можно найти по ссылке.
|
Работа с выборкой из множества строк
Пример работы с выборкой из множества строк можно найти по ссылке.
|