книги / Моделирование и оптимизация в LINGO
..pdfРис. 12
Рис. 13
91
8.3. Взаимодействие с базами данных
LINGO поддерживает обращение к любой СУБД, имеющей стандартизированный интерфейс ODBC. Такую связь обеспечивает функция @ODBC, которая используется для импорта данных из БД и экспорта данных в любую БД с ODBC. Пока эта функция доступна только в версии под Windows.
При импорте из БД функция @ODBC размещается в разделе DATA и записывается согласно синтаксису:
object_list = @ODBC([ꞌdata_sourceꞌ[,ꞌtable_nameꞌ [,ꞌcolumn_name_1ꞌ [,ꞌcolumn_name_2ꞌ …]]]]);
Здесь object_list – это список импортируемых объектов, определенных на одном и том же множестве, а смысл аргументов функции ясен из их обозначения. Источник данных (data_source) создается под БД конкретной СУБД.
Если все аргументы опущены, то импортируются объекты, имеющие имена, перечисленные в object_list, при этом источник данных определяется по имени модели, следующей за словом Title. Если опущено имя таблицы, то импортируемые объекты определяются по именам в object_list.
Примеры:
TRANS_COST =
@ODBC( 'TRANSPORTATION', 'ARC','COST');
В этом примере значения атрибута TRANS_COST извлекаются из столбца COST таблицы ARC, которая содержится в источнике данных TRANSPORTATION.
Другой пример:
VOLUME, WEIGHT, LENGTH = @ODBC( 'MOBIL', 'PARAM');
Здесь опущены имена столбцов таблицы PARAM, входящей
висточник данных MOBIL. Поэтому LINGO берет имена атрибутов
влевой части выражения в качестве имен столбцов таблицы PARAM. Еще один пример импорта и экспорта будет показан ниже
вмодели Production.
92
При экспорте решений из LINGO в БД синтаксис функции имеет вид
@ODBC( ['data_source'[, 'table_name'[, 'column_name_1'[,…, 'column_name_n']]]]) = object_list;
В этом случае object_list содержит список экспортируемых объектов, определенных на одном множестве, а аргументы функции указывают места в БД, куда должны записываться эти объекты. Допускается отсутствие части или всех аргументов, тогда они определяются по имени модели и именам в object_list (так же, как при импорте).
Пример:
@ODBC('TRANSPORTATION',
'ARC', 'VOLUME') = VOLUME;
Когда нужно экспортировать только части атрибутов или величины, вычисляемые по значениям атрибутов, приходится использовать функцию @WRITEFOR, которая обеспечивает такую обработку атрибутов. В этом случае применяется вторая форма синтаксиса функции @ODBC:
@ODBC( 'data_source', 'table_name', 'column_name_1'[,…, 'column_name_n']) = @WRITEFOR( setname
[ ( set_index_list) [ | conditional_qualifier]] : output_obj_1[,…, output_obj_n]);
Здесь перечень output_obj содержит экспортируемые объекты. Пример:
@ODBC( 'TRANSPORTATION',
'SOLUTION', 'FROM', 'TO', 'VOLUME') = @WRITEFOR( ARC( I, J) | VOLUME( I, J) #GT# 0:
WAREHOUSE( I), CUSTOMER( J), VOLUME( I, J));
В этом примере экспортируются только ненулевые значения атрибута VOLUME в одноименный столбец таблицы SOLUTION, а поставщики и потребители в столбцы FROM и TO соответственно.
Если столбец таблицы содержит больше строк, чем число записываемых в него значений, лишние ячейки столбца остаются нетронутыми, либо при включенном параметре Fill Out Ranges and Tables их содержимое стирается.
93
8.3.1. Установка взаимодействия LINGO и БД
Всю процедуру установки взаимодействия LINGO и БД покажем на примере нашей задачи Production, листинг модели которой приведен ниже:
MODEL:
Title Production; sets:
PRODUCT: order;
EQUIPMENT /Eq1..Eq3/: TWORK, K;
PR_EQ (PRODUCT, EQUIPMENT): T, X; endsets
data:
! Импортэлементовмножества, матрицывременизначенийзаказов;
PRODUCT, order= @ODBC(); T=@ODBC();
K = @ODBC();
! Экспорт решения;
@ODBC()=X; @ODBC()= TWORK; enddata
MIN = TIME;
@FOR(PRODUCT(I)|order #NE# 0: @SUM(EQUIPMENT(J): X(I,J))=order);
@FOR(EQUIPMENT(J): @SUM(PRODUCT(I)|order #NE# 0: T(I,J)*X(I,J))- TWORK(J)=0);
TIME = @MAX(EQUIPMENT: TWORK); @FOR(PR_EQ(I,J)|order(I) #NE# 0: @GIN(X));
@FOR( EQUIPMENT(J): @CARD( 'name'+ EQUIPMENT(J), K); @FOR( PRODUCT(I)|order #NE# 0: @CARD('name'+ EQUIP-
MENT(J), X(I,J))
)
); END
В этой модели все исходные данные извлекаются из БД и решение записывается в БД с помощью функции @ODBC, размещенной в разделе DATA. Заметим, что в левой части выражения для получения данных из БД могут стоять только объекты из одного родительского множества. Аналогичное правило действует для правой части выражения, определяющего запись в БД. При этом, как при импорте, так и при экспорте аргументы функции @ODBC в этой
94
модели опущены, но они определяются по именам, записанным в левой части выражения при импорте и в правой при экспорте.
Взаимодействие LINGO и БД базируется на источнике данных ODBC, которым является БД с интерфейсом ODBC. Но следует иметь в виду, что базы данных в СУБД с включенной поддержкой ODBC не квалифицируются как источник данных ODBC, пока они не зарегистрированы администратором ODBC. Далее мы рассмотрим процесс регистрации для баз данных Microsoft Access, Oracle и SQL Server и решение задач с их использованием.
8.3.2. Создание источника данных ODBC на примере БД Access
Предполагается, что в Access уже создана база данных. Так, для нашей задачи имеем БД Productionbd, которая состоит из трех таблиц, содержащих исходные данные и поля для результатов реше-
ния (TWORK и X) (рис. 14).
Рис. 14
95
Чтобы эта БД квалифицировалась как источник данных ODBC, сначала в панели управления компьютера открываем папку
Администрирование и в ней находим значок Источники данных
(ODBC). Затем двойным кликом на значке открываем окно Админи-
стратор источников данных ODBC, в котором нажимаем кнопку Добавить. В результате появляется окно Создание нового источника данных. В нем представлены имеющиеся на компьютере драйверы,
среди которых выбираем Microsoft Access Driver (рис. 15).
Рис. 15
Закрытие этого окна кнопкой Готово приводит к появлению окна установки драйвера, первоначально не содержащего адреса БД
(рис. 16).
Вполе Имя источника записываем имя задачи, указанное
вмодели после служебного слова Title (это обязательное требование). Также заполняем поле Описание и нажимаем кнопку Выбрать. В появившемся окне находим путь к файлу БД, закрываем окно, и адрес БД появляется в окне Установка драйвера, как показано выше. Нажатием ОК завершаем создание нового источника данных.
96
Рис. 16
Чтобы убедиться в этом, возвращаемся к окну Администратор источников данных ODBC, в котором видим наш источник Production (рис. 17).
Рис. 17
97
Теперь запускаем решение задачи и получаем отчет о решении, отличающийся от стандартного добавлением информации об экспорте, отдельно для каждого атрибута под заголовком Export Summary Report. Скриншот решения в LINGO показан на рис. 18.
Рис. 18
Открыв в Microsoft Access нашу БД, увидим, что поля TWORK и X содержат результаты решения задачи (рис. 19).
Таким образом, проиллюстрирован весь ход установки взаи-
модействия между LINGO и БД в Microsoft Access.
98
Рис. 19
8.3.3. Использование БД ORACLE
Создание источника данных ODBC на БД Oracle аналогично вышеописанному подходу для Access, но из драйверов следует вы-
бирать только Microsoft ODBC for Oracle.
В качестве примера снова обратимся к задаче Production. В модели задачи в конце имен таблиц, множеств и атрибутов добавим символ “s” для устранения совпадений со служебными словами SOL. Для работы с Oracle воспользуемся удобной средой TOAD for Oracle. Пишем в редакторе запрос на создание трех таблиц в имею-
щейся БД Library:
CREATE TABLE PRODUCTS |
|
|
( |
CHAR(32) |
NOT NULL, |
PRODUCTS |
||
ORDER1 |
NUMBER |
NOT NULL |
); |
|
|
CREATE TABLE EQUIPMENTS
(
99
EQUIPMENTS |
CHAR(32) |
NOT NULL, |
K |
NUMBER |
NOT NULL, |
TWORK |
NUMBER |
NOT NULL |
); |
|
|
CREATE TABLE PR_EQS |
|
|
( |
CHAR(32) |
NOT NULL, |
PRODUCTS |
||
EQUIPMENTS |
CHAR(32) |
NOT NULL, |
T |
NUMBER |
NOT NULL, |
X |
NUMBER |
NOT NULL |
); |
|
|
COMMIT;
DELETE FROM PRODUCTS;
DELETE FROM EQUIPMENTS;
DELETE FROM PR_EQS;
COMMIT;
INSERT INTO PRODUCTS VALUES ('Pr1', 73);
INSERT INTO PRODUCTS VALUES ('Pr2', 123);
INSERT INTO PRODUCTS VALUES ('Pr3', 0);
INSERT INTO PRODUCTS VALUES ('Pr4', 62);
COMMIT;
INSERT INTO EQUIPMENTS VALUES ('Eq1', 2, 0);
INSERT INTO EQUIPMENTS VALUES ('Eq2', 1, 0);
INSERT INTO EQUIPMENTS VALUES ('Eq3', 3, 0);
COMMIT;
INSERT INTO PR_EQS VALUES ('Pr1', 'Eq1', 7, 0);
INSERT INTO PR_EQS VALUES ('Pr1', 'Eq2', 11, 0);
INSERT INTO PR_EQS VALUES ('Pr1', 'Eq3', 9, 0);
INSERT INTO PR_EQS VALUES ('Pr2', 'Eq1', 14, 0);
INSERT INTO PR_EQS VALUES ('Pr2', 'Eq2', 8, 0);
INSERT INTO PR_EQS VALUES ('Pr2', 'Eq3', 10, 0);
INSERT INTO PR_EQS VALUES ('Pr3', 'Eq1', 12, 0);
INSERT INTO PR_EQS VALUES ('Pr3', 'Eq2', 7, 0);
INSERT INTO PR_EQS VALUES ('Pr3', 'Eq3', 13, 0);
INSERT INTO PR_EQS VALUES ('Pr4', 'Eq1', 10, 0);
INSERT INTO PR_EQS VALUES ('Pr4', 'Eq2', 9, 0);
INSERT INTO PR_EQS VALUES ('Pr4', 'Eq3', 11, 0);
COMMIT;
100