跳到主要内容

数据库导入向导

Darra PLC IDE 内置"数据库导入向导", 把一张 SQL 表的结构直接翻译成 PLC 的 DB (数据块定义) + 一套标准读写 FB, 省去手写绑定的重复劳动。

向导的核心用途

向导生成的是 PLC 的 DB 块定义, 让 PLC 程序可以直接通过 DB_Recipe.Param1 等变量名访问数据库字段。 不是生成业务 CRUD 界面, 也不是生成业务 API 后端。 典型场景: 把上位的配方/工单表结构在 PLC 工程里复刻成 DB 块, PLC 程序用标准读 FB 把数据拉进来。

适用场景

  • 上位系统的配方表结构导入 PLC → 生成对应 DB 块 + 读 FB
  • 工单只读视图导入 PLC → 生成工单 DB 块, PLC 读取当前任务
  • 设备参数表导入 PLC → 用 DB 块承载静态工艺参数
  • 生成少量写 FB 用于班次汇总 / 换型审计 这类低频写入
  • 老系统迁移: 原本用 Excel 表维护配方, 改为关系型数据库

前置准备

开始之前确认:

要求
数据库连接已配置到工程, 见 数据库
目标表存在, 有 PRIMARY KEY
账号权限至少 SELECT 权限, 如需写入需 INSERT/UPDATE/DELETE
网络连通IDE 能访问数据库服务器 (诊断: 连接管理器 → 测试连接)
字段类型使用 Darra 支持的类型 (见 字段映射)

一步式流程总览

步骤 1: 启动向导

打开向导的两种方式:

  1. 从通讯节点: 项目树 → 通讯 → 已配数据库 → 右键 → 导入为 DB
  2. 从 Ribbon: Ribbon → PLC → 导入 → 数据库表

截图占位: TODO 向导入口截图

步骤 2: 选择数据源

向导首页列出工程里所有已配置的数据库连接:

说明
连接名例如 db_recipe, db_workorder
引擎SQLite / SQL Server / MySQL / PostgreSQL / Oracle
主机服务器 IP 或主机名
数据库目标数据库/Schema
状态在线 / 离线 (连不上的禁用)

选择目标连接, 点"下一步"。

如果还没配置连接, 点"新建连接"走完整配置:

字段说明
连接名工程内唯一
引擎下拉选
服务器IP:端口
数据库名称
用户 / 密码或 Windows 集成认证
SSL如需加密

点"测试连接", 绿色打勾后保存。

截图占位: TODO 连接选择页面截图

步骤 3: 选择表

向导查询 INFORMATION_SCHEMA 或类似系统视图列出所有表:

说明
表名schema.table 全限定
行数估计近似值
列数字段数
有主键是 / 否 (无主键的需手工选择键列)
说明表注释 (如果数据库里配了)

树形或列表视图, 支持:

  • 搜索过滤
  • 按 schema 分组
  • 收藏常用表

勾选一张或多张表 (支持多选批量导入), 点"下一步"。

截图占位: TODO 表选择页面截图

步骤 4: 字段映射

这一步决定每个 SQL 字段如何对应到 PLC 变量。左侧是数据库列, 右侧是对应的 PLC 定义:

SQL 字段SQL 类型PLC 名称PLC 类型是否主键读写权限注释
idINTRecipeIdDINT只读主键
codeVARCHAR(32)RecipeCodeSTRING[32]读写配方编码
speedDECIMAL(6,2)SpeedREAL读写运行速度
pressureFLOATPressureREAL读写气压
activeBITIsActiveBOOL读写启用
updated_atDATETIMEUpdatedAtDT只读更新时间

默认规则 (见 字段映射):

  • 整数: TINYINT → USINT, SMALLINT → INT, INT → DINT, BIGINT → LINT
  • 浮点: FLOAT/REAL → REAL, DOUBLE → LREAL, DECIMAL(p,s) → REAL (精度可能丢失)
  • 字符串: VARCHAR(N) → STRING[N]
  • 时间: DATETIME → DT, DATE → DATE, TIME → TIME
  • 布尔: BIT / BOOLEAN → BOOL

向导自动填写, 用户可改。右侧显示每行的"警告":

  • 精度丢失 (DECIMAL 转 REAL)
  • 长度截断 (VARCHAR(1000) → STRING[255])
  • 类型不安全 (BLOB → ARRAY OF BYTE, 需要手动处理长度)

截图占位: TODO 字段映射页面截图

自定义名称

默认 PLC 名称 = SQL 字段名转 PascalCase。可改为:

  • 业务名 (例如 runSpeedSpeed_mpm)
  • 加前缀 (例如 Recipe_Speed)
  • 批量: 点 "批量改名", 用规则 {FieldName}_{Unit}

排除字段

不需要的字段点行首的 "排除" 按钮, 变灰后不出现在最终 DB 里。典型排除:

  • created_by / modified_by (操作员字段)
  • BLOB / LONG TEXT 字段
  • 纯内部字段 (如 version, deleted_flag)

步骤 5: 生成选项

最后一步确认生成什么:

DB 块

每张表生成一个 DB, 名称 = DB_<TableName>, 包含表结构对应的所有字段:

DATA_BLOCK DB_Recipes
VAR
RecipeId : DINT;
RecipeCode : STRING[32];
Speed : REAL;
Pressure : REAL;
IsActive : BOOL;
UpdatedAt : DT;

(* 操作状态 *)
LastError : STRING[128];
LastRead : DT;
LastWrite : DT;
END_VAR
END_DATA_BLOCK

读取 FB

自动生成 FB_ReadRecipes:

FUNCTION_BLOCK FB_ReadRecipes
VAR_INPUT
Execute : BOOL; (* 上升沿触发 *)
FilterId : DINT := 0; (* 0 = 全部, >0 = 按 ID 查 *)
FilterCode : STRING[32] := ''; (* 非空 = 按 code 查 *)
END_VAR
VAR_OUTPUT
Done : BOOL;
Busy : BOOL;
Error : BOOL;
ErrorMessage : STRING[128];
RowCount : INT;
END_VAR
VAR
Select : DB_SELECT;
State : INT;
StartEdge : R_TRIG;
END_VAR

StartEdge(CLK := Execute);

CASE State OF
0: (* 空闲 *)
IF StartEdge.Q THEN
Busy := TRUE;
Error := FALSE;
Done := FALSE;
State := 10;
END_IF;

10: (* 执行查询 *)
Select(
ConnectionName := 'db_recipe',
SQL := 'SELECT id, code, speed, pressure, active, updated_at ' +
'FROM recipes WHERE (:id = 0 OR id = :id) ' +
'AND (:code = '''' OR code = :code)',
Execute := TRUE
);
Select.BindInt('id', FilterId);
Select.BindString('code', FilterCode);
State := 20;

20: (* 等待完成 *)
Select(Execute := FALSE);
IF Select.Done THEN
IF Select.RowCount > 0 THEN
DB_Recipes.RecipeId := Select.Row[0].Cell[0].AsDInt;
DB_Recipes.RecipeCode := Select.Row[0].Cell[1].AsString;
DB_Recipes.Speed := Select.Row[0].Cell[2].AsReal;
DB_Recipes.Pressure := Select.Row[0].Cell[3].AsReal;
DB_Recipes.IsActive := Select.Row[0].Cell[4].AsBool;
DB_Recipes.UpdatedAt := Select.Row[0].Cell[5].AsDT;
END_IF;
RowCount := Select.RowCount;
DB_Recipes.LastRead := NOW();
Done := TRUE;
Busy := FALSE;
State := 0;
ELSIF Select.Error THEN
Error := TRUE;
ErrorMessage := Select.ErrorMessage;
DB_Recipes.LastError := Select.ErrorMessage;
Busy := FALSE;
State := 0;
END_IF;
END_CASE;
END_FUNCTION_BLOCK

写入 FB

FB_WriteRecipes (如表在映射里设为读写):

FUNCTION_BLOCK FB_WriteRecipes
VAR_INPUT
Execute : BOOL;
WriteMode : INT := 0; (* 0=INSERT, 1=UPDATE, 2=UPSERT *)
END_VAR
VAR_OUTPUT
Done : BOOL;
Error : BOOL;
AffectedRows : INT;
NewInsertId : DINT;
END_VAR
VAR
Insert : DB_INSERT;
Update : DB_UPDATE;
Upsert : DB_EXECUTE;
(* ... *)
END_VAR
(* 略 *)
END_FUNCTION_BLOCK

删除 FB

如勾选"生成删除", 生成 FB_DeleteRecipes, 支持按主键或条件删除。

列表 FB

生成 FB_ListRecipes 返回 N 行数据, 用于配方列表显示:

FUNCTION_BLOCK FB_ListRecipes
VAR_INPUT
Execute : BOOL;
MaxRows : INT := 100;
WhereClause : STRING[256] := '';
END_VAR
VAR_OUTPUT
Done : BOOL;
Count : INT;
Rows : ARRAY[0..99] OF TYPE_Recipes; (* UDT, 字段结构 *)
END_VAR
(* ... *)
END_FUNCTION_BLOCK

步骤 6: 预览与确认

向导生成代码预览, 显示:

  • DB 结构 (新增 / 修改 字段对比)
  • 所有 FB 的源码 (只读预览)
  • 变量表新增项
  • SQL 语句

逐项检查无误后点 "生成"。

截图占位: TODO 预览页面截图

步骤 7: 生成完成

向导关闭, 项目树自动更新:

MyProject/
├─ 程序块/
│ ├─ DB_Recipes (新增)
│ └─ 函数块/
│ ├─ FB_ReadRecipes (新增)
│ ├─ FB_WriteRecipes (新增)
│ ├─ FB_ListRecipes (新增)
│ └─ FB_DeleteRecipes (新增)
├─ 数据类型/
│ └─ TYPE_Recipes (新增 UDT)
└─ 变量表/
└─ 全局变量 (更新)

立即可编译下载。

使用生成的代码

读取当前激活配方

VAR
ReadRecipe : FB_ReadRecipes;
Trig : BOOL;
END_VAR

ReadRecipe(
Execute := Trig,
FilterCode := 'RECIPE_A'
);

IF ReadRecipe.Done THEN
(* 读取完成, DB_Recipes 已填充 *)
(* 用 DB_Recipes.Speed 等字段 *)
END_IF;

写入生产记录

VAR
WriteLog : FB_WriteProduction;
END_VAR

WriteLog(
Execute := PartCompleted,
WriteMode := 0 (* INSERT *)
);

IF WriteLog.Done THEN
LastInsertedId := WriteLog.NewInsertId;
END_IF;

再次导入 (结构变更)

数据库表结构变了怎么办?

  1. 再次运行向导, 选同一张表
  2. 向导检测到已存在的 DB, 显示"结构对比"页面:
    • 新增字段 (绿色)
    • 删除字段 (红色删除线)
    • 类型变化 (橙色)
    • 重命名 (紫色)
  3. 选择处理策略:
    • 智能合并 (推荐): 保留人工改过的 FB 代码, 只更新结构相关部分
    • 完全覆盖: 重新生成所有文件 (人工改动丢失)
    • 导出差异: 输出 diff 让人工合并

批量导入

一次导入多张表:

  1. 步骤 3 时勾选多张
  2. 字段映射页按 Tab 切换不同表
  3. 生成时一次性产出多组文件

适合批量导入产线所用的多张配方/工单/BOM 表结构。

导入模板

常改的配置 (连接 + 表集合 + 命名规则) 可以保存为模板:

向导底部 → 保存为模板
→ 起名: "产线 A 配方与工单"
→ 下次打开向导时选"从模板", 一键进入预览

诊断与排错

症状原因处理
表列表为空账号无 INFORMATION_SCHEMA 权限赋予 SELECT 权限或联系 DBA
字段映射有警告 "精度丢失"DECIMAL(18,10) → REAL (7位有效)改用 LREAL, 或在 SQL 端用 CAST
生成后编译报错 "DB 已存在"同名 DB 冲突覆盖或改名
FB_Read 超时SQL 复杂或表大加索引, 或加 LIMIT
中文字段名被截断SQL 用 UTF-8, PLC 字符串默认配置连接为 CharSet=utf8mb4
主键为复合键向导只支持单主键手工修改生成的 FB 的 WHERE

最佳实践

  1. 先在数据库端规范化: 设好主键、外键、NOT NULL, 向导才能生成好代码
  2. 字段名英文: 中文字段名在多环境兼容性差, 英文更稳
  3. 有版本列: 每张配方/工单表加 version INTupdated_at, 方便乐观锁
  4. 分读写角色: 读 FB 用只读账号, 写 FB 用读写账号, 部署时 IDE 侧单独配连接
  5. 避免大字段: TEXT / BLOB 字段不要导入 PLC, 用另一张元数据表索引
  6. 批量操作: 批量 FB 用于班次结束的汇总写入 (一次写 N 行), 不是扫描周期内反复调用; 高频变量归档请走 异步数据管道

相关文档