Database 手册 · Chapter 6

SELECT 模式

读取 SQL 归纳为两种流程。

模式API用途
A) 单值RunSqlScalarInt(sql)COUNT(*) 这样单格结果
B) 批量 SELECTRunSqlSelect(sql) + RowCount + GetRowArray(i) / GetValue(i, col)填充 DataGrid、多行处理

示例项目两种都用到。


模式 A — 单值查询

DB_Open() 中的空表检查是典型例子。

int rowCnt = DB["local"].RunSqlScalarInt("SELECT COUNT(*) FROM order_history");
if( rowCnt == 0 )
{
   DB_InsertInitialSamples();
}

按类型的函数:

函数返回类型
RunSqlScalarInt(sql)int
RunSqlScalarDouble(sql)double
RunSqlScalar(sql)string(通用)

查询为空时返回 0 / 0.0 / ""。失败与否用 LastError 判定。


模式 B — 批量 SELECT(DB_Refresh)

示例的 DB_Refresh() 展示标准流程。

FUNCTION DB_Refresh()
{
   if( DB["local"].IsOpen == false )
   {
      LogError($"DB_Refresh : DB is not open");
      return false;
   }
 
   string sql = "SELECT id, order_no, menu_name, start_time, end_time, weight_g, result, is_error FROM order_history ORDER BY id ASC";
   if( DB["local"].RunSqlSelect(sql) == false )
   {
      LogError($"DB_Refresh select failed : {DB["local"].LastError}");
      return false;
   }
 
   DispData.Clear();
 
   int rows = DB["local"].RowCount;
   for( i, 0, rows-1 )
   {
      // GetRowArray : 按列顺序返回一行的 XArray
      // 一条 CSV 行(用逗号拼接)= DataGrid 一行
      array row = DB["local"].GetRowArray(/*row*/i);
      string line = $"{row[0]},{row[1]},{row[2]},{row[3]},{row[4]},{row[5]},{row[6]},{row[7]}";
      DispData.Add(line);
   }
 
   Log($"DB_Refresh : {rows} rows loaded");
   return true;
}

4 步流程

  1. RunSqlSelect(sql) — 把结果缓存到内存。false 为失败。
  2. RowCount — 已缓存结果的行数。
  3. GetRowArray(i) — 第 i 行按列顺序返回为 array
  4. 结果转换 — 此处拼成一条 CSV 行加入 DispData

结果缓存在下次 SELECT 执行或连接关闭之前一直有效。

单元格访问

不按行而按单元格读取时:

DB["local"].RunSqlSelect("SELECT id, menu_name, weight_g FROM order_history WHERE id=?", p);
 
int    id   = DB["local"].GetValueInt(/*row*/0, /*colName*/"id");
string menu = DB["local"].GetValue(/*row*/0, /*colName*/"menu_name");
double w    = DB["local"].GetValueDouble(/*row*/0, /*colName*/"weight_g");

示例的 DB_OpenModifyDlg(第 7 章)就是用这种模式把选中行的所有列复制到编辑字段(Edit*)。

函数含义
GetValue(row, col)字符串(通用)
GetValueInt(row, col)整数
GetValueDouble(row, col)浮点
GetValueBool(row, col)布尔

row 从 0 开始计数,col 既可用列也可用索引(推荐用名 — 列顺序变了也安全)。


常用 SELECT 形式

按示例领域 — 可直接复制粘贴试用:

// 1) 最近 50 条(用于 DataGrid)
"SELECT id, order_no, menu_name, end_time, result " +
"FROM order_history ORDER BY id DESC LIMIT 50"
 
// 2) 按结果分组统计
"SELECT result, COUNT(*) FROM order_history GROUP BY result"
 
// 3) 仅看错误
"SELECT id, order_no, menu_name FROM order_history WHERE is_error = 1"
 
// 4) 时间范围
"SELECT id, order_no FROM order_history " +
"WHERE start_time >= ? AND start_time <  ?"
// → 第二个参数传 [from, to] 数组给 RunSqlSelect

参数化 SELECT

RunSqlSelect 同样可以在第二参数接收参数数组 — 与 INSERT/UPDATE 相同模式。

array p[] = {""};
p.Clear();
p.Add(targetId);
 
DB["local"].RunSqlSelect("SELECT * FROM order_history WHERE id=?", p);
 
if( DB["local"].RowCount == 1 )
{
   string menu = DB["local"].GetValue(0, "menu_name");
   // ...
}

常见陷阱

  • RowCount 仅在 SELECT 之后有意义 — INSERT / UPDATE 后必须再次 SELECT 才能取到准确行数。示例通过让所有变更函数最后都调用 DB_Refresh() 自动解决。
  • SELECT 中明确写出列名SELECT * 在不同环境列顺序可能不同,使用 GetRowArray 按索引访问时危险。
  • 空结果RowCount == 0 时调用 GetValue(0, ...) 返回空字符串,但逻辑上是无意义调用,务必加守卫。

下一章

读写代码都齐了,接下来是把数据放到画面上 — 只需变更 DispData 一个数组,XDataGrid 就会自动刷新。该绑定是下一章的主题。