跳转到内容

GLPK/Table 语句

来自维基教科书,开放的书籍,开放的世界

Table 语句可用于将数据从外部数据源读入模型对象,包括集合和参数。Table 语句还可用于将模型结果写回外部数据源。当前为ODBC数据库,尤其是MySQL数据库,CSV文件,以及dBase文件提供驱动程序。

官方文档

[编辑 | 编辑源代码]

GLPK 官方文档文件doc/gmpl.pdf(在 GLPK 4.45 之前doc/tables.pdf) 包含 GMPL 表功能的完整参考。请参阅获取 GLPK。此页面仅提供指针和示例。

从 4.45 版开始,以下信息丢失了
字段名由字母 [A-Z,a-z] 和数字 [0-9] 字符组成,区分大小写。它不需要是唯一的[1]

逗号分隔值 (CSV) 文件的格式在RFC 4180[1]中描述。

对于 CSV 文件,驱动程序标识符为“CSV”。table OUT 语句将完全替换任何现有文件。

CSV 表驱动程序具有以下内置限制

  • 列数必须小于或等于 50。
  • 每个值的长度必须小于或等于 100 个字符。

以下示例展示了 CSV 文件的读取和写入

# test1.mod writes CSV file
set I := {1..300};
set J := {1..20};
set K := {1..100};
param  x{I,J,K} := Uniform01();
table tout {i in I, j in J, k in K} OUT "CSV" "test.csv" :
i, j, k, x[i,j,k];
end;
# test2.mod reads CSV file
set I, dimen 3;
param  x{I};
table tin IN "CSV" "test.csv" :
I <- [i,j,k], x;
printf "Number of values: %d\n", card(I);
printf "Average value: %f\n", (sum{(i,j,k) in I} x[i,j,k]) / card(I);
end;

对于dBase文件,驱动程序标识符为“xBASE”。table OUT 语句将完全替换任何现有文件。

dBase 表驱动程序具有以下内置限制

  • 列数必须小于或等于 50。
  • 每个值的长度必须小于或等于 100 个字符。

对于ODBC数据库连接,驱动程序标识符为“ODBC”。对于本机MySQL数据库连接,驱动程序标识符为“MySQL”。

请注意,table UPDATE 和 table INSERT 语句必须后跟 table OUT 语句才能生效(如执行 SQL部分所述)。

使用 MySQL 表驱动程序时,table 语句可以充分利用连接的数据库提供的SQL命令。MySQL REPLACE 语句是 SQL 的非标准扩展,它意味着随后的 table OUT 语句。

table IN 语句与其他 SQL 语句结合使用,可用于从关系数据库中选择数据。例如

set I, dimen 2;
param st{I};
table t IN
  'ODBC' 'FILEDSN=supply.dsn'
  'SELECT product, period, quantity'
  '  FROM stock' :
  I <- [product, period], st ~ quantity;

不用 SELECT 语句,可以提供表名。在这种情况下,将选择整个表。

set I, dimen 2;
param st{I};
table t IN
  'ODBC' 'FILEDSN=supply.dsn'
  'stock' :
  I <- [product, period], st ~ quantity;

SELECT 语句(或表名)可以由其他 SQL 语句作为前缀

set I, dimen 2;
param st{I};
table t IN
  'ODBC' 'FILEDSN=supply.dsn'
  'DROP TABLE IF EXISTS result;'
  'CREATE TABLE result ('
  '  product  TEXT(40),'
  '  period   INTEGER,'
  '  quantity FLOAT,'
  '  PRIMARY KEY ( product(40), period ) );'
  'SELECT product, period, quantity'
  '  FROM stock' :
  I <- [product, period], st ~ quantity;

可以将 SQL 语句拆分为多个字符串以克服 GLPK 中100 个字符单行字符串长度限制。在这种情况下,SQL 语句的终止由在多行调用(如上所示)的最后一个字符中存在未加引号的分号来指示。

从 GLPK 4.44 开始,GLPK 使用 ODBC 和 MySQL 驱动程序时,会自动从字符串中修剪尾随空格 (0x20) 字符。strtrim()函数。

table OUT

[编辑 | 编辑源代码]

table OUT 语句与其他 SQL 语句结合使用,可用于在关系数据库中插入、更新或删除记录。

INSERT 语句可用于将记录插入关系数据库。例如

table t {p in P, t in T} OUT
  'ODBC' 'FILEDSN=supply.dsn'
  'INSERT INTO stock'
  '  ( product, period, quantity) '
  '  VALUES (?,?,?)' :
  p, t, st[p, t];

如果最后一个 SQL 语句不包含作为值占位符的问号,则需要表名。该表名和提供的列名将用于构建 INSERT 语句。

table t {p in P, t in T} OUT
  'ODBC' 'FILEDSN=supply.dsn'
  'stock':
  p ~ product, t ~ period, st[p, t] ~ quantity;

迭代的最终 SQL 语句可以由其他 SQL 语句作为前缀

table t {p in P, t in T} OUT
  'ODBC' 'FILEDSN=supply.dsn'
  'DELETE FROM stock;'
  'INSERT INTO stock'
  '  ( product, period, quantity) '
  '  VALUES (?,?,?)' :
  p, t, st[p, t];

这种策略可以用于避免重复插入。

可以发出 INSERT 以外的语句。例如,UPDATE 语句可用于更新关系数据库中的记录。例如

table t {p in P, t in T} OUT
  'ODBC' 'FILEDSN=supply.dsn'
  'UPDATE stock'
  '  SET quantity = ?'
  '  WHERE'
  '    product = ? AND period = ?;' :
  st[p, t], p, t;

DELETE 语句可用于从关系数据库中删除记录。例如

table t {p in P, t in T} OUT
  'ODBC' 'FILEDSN=supply.dsn'
  'DELETE FROM stock'
  '  WHERE'
  '    product = ? AND period = ?;' :
  p, t;

执行 SQL

[编辑 | 编辑源代码]

目前,GMPL 语言中的 SQL 支持仅允许在“table IN”和“table OUT”语句块中发出 SQL 命令。

在“table IN”块中,最终的 SELECT 语句(或表名)可以由任意数量的准备 SQL 语句作为前缀。

在“table OUT”块中,迭代域的最终 INSERT/DELETE/UPDATE 语句可以由任意数量的准备 SQL 语句作为前缀。

为了将准备语句与数据库 I/O 完全分开,可以使用虚拟输出语句

table prep {i in 1..1} OUT 'ODBC'
  'DSN=glpk;UID=glpk;PWD=gnu'
  # The preparatory SQL statement(s) follow
  'DELETE FROM stock;'
  # The next SQL statement is needed to satisfy the GMPL syntax.
  'SELECT ?;' : i; 

Table 语句错误(已在 GLPK 4.45 中修复)

[编辑 | 编辑源代码]

在 4.45 版之前的 GLPK 版本中,处理 table 语句时可能会遇到内存溢出错误。该问题在此主题中进行了描述,现在已解决。

参考文献

[编辑 | 编辑源代码]
  1. Y. Shafranovich (October 2005). "Common Format and MIME Type for Comma-Separated Values (CSV) Files".
华夏公益教科书