Database
把工厂系统保存在数据库表中的值(SQL Server、PostgreSQL、MySQL 和 MariaDB、SQLite,或通过 ODBC 访问的任何数据库)读成点位,并在点位要求的地方写回:“数据库”和“登录”卡片,按表、列和行读取单元格或执行自定义查询的点位,点位写入的两种方式,为每一列提供一个点位的扫描,四个完整示例,以及驱动不做的事。
Database 驱动读取工厂系统保存在数据库表中的值:MES 保存的生产订单,ERP 保存的配方或设定值,另一个测试系统记录的结果。每个点位读取一个表中的一个值,它的值和其他任何点位的值一样送达各处:Logic、仪表画面,以及 Process 测试台的运行记录。在点位要求时,驱动也会写回:写入点位所读取的单元格,或通过点位自己的命令写入。
SQL Server、PostgreSQL、MySQL 和 MariaDB 以及 SQLite 无需在计算机上安装任何东西即可连接。其他数据库(Oracle、Access、Firebird 等)通过它们自己的 ODBC 驱动连接,该驱动的 64 位版本必须安装在计算机上。
读取是主要用途,路径很短:设备说明其数据库在哪里以及工作站如何登录,扫描为其各表的每一列提供一个点位,每个点位新建时都是只读。属于写入的内容,只有在点位的访问方式允许工作站写入之后才会出现在该点位上。
此驱动的一台设备就是一个数据库:同一服务器上的两个数据库就是两台设备。设备位于驱动之下,可以归入文件夹,驱动 → 文件夹 → 设备 → 点位,和任何没有串行线路或 Broker 的驱动一样。
驱动页面
标题下面的一行写着“每台设备读取一个数据库。添加设备,填写其数据库的位置和工作站的登录方式,然后扫描它,把其中的列添加为点位。”有配置 Connector 的权限时,页面上有此驱动自己的扫描范围卡片,其中是扫描要读取其数据库的设备(参见设备发现)。下面是和任何驱动一样的设备表(参见设备表),用标题右侧的添加设备增加设备;表为空时显示“还没有设备。”驱动的工具栏上有发现设备,在扫描范围卡片填写完整之前是灰色的。此驱动列在文件和数据库之下,位于 File 驱动旁边。
设备
此驱动的设备没有“连接”卡片:取而代之的是数据库卡片,除了没有登录的 SQLite 之外,其后还有登录卡片。“设备”卡片的轮询间隔(ms)默认为 1000,表示点位读取数据库的频率,和任何驱动一样,每个点位都可以覆盖它。
新设备是一台没有服务器的 SQL Server:它显示“尚未填写服务器”,其页面显示“在这台设备说明其数据库的位置之前,工作站不会连接它,因此暂时不读取任何数据,也没有错误可显示。在下面的‘数据库’卡片里填写(服务器和数据库名称、文件或数据源),工作站就会连接。”在说明位置之前不读取任何内容。标题中显示的基础 URI 是运行时地址,从不包含用户或密码:SQL Server 实例为 database://sqlserver?server=mes-sql&instance=SQLEXPRESS&database=MES,SQLite 文件为 database://sqlite?file=C%3A%5CData%5Crecipes.db,ODBC 数据源为 database://odbc?source=ERP。
“数据库”卡片
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 数据库类型 | 始终 | SQL Server、PostgreSQL、MySQL / MariaDB、SQLite 或 其他(ODBC),后者显示“使用此计算机上为该数据库安装的 64 位 ODBC 驱动(Oracle、Access、Firebird 等)。” | SQL Server |
| 服务器 | SQL Server、PostgreSQL、MySQL / MariaDB | 在 SQL Server 上:“主机名或 IP 地址。SERVER\INSTANCE 和 SERVER,PORT 会拆分到各自的框中。”在另外两种上:“主机名或 IP 地址。冒号后写的端口会移到‘端口’框。” | 空 |
| 端口 | 同上 | 留空即数据库自己的端口,空框中会显示该端口:1433、5432 或 3306。SQL Server 实例没有端口时,框中不显示任何内容,由服务器的 SQL Server Browser 告知端口。 | 空 |
| 实例名称 | SQL Server | “默认实例留空。没有端口的命名实例通过 SQL Server Browser 查找。”最多 16 个字母、数字、_ 和 $,以字母或 _ 开头。 |
空 |
| 数据库名称 | SQL Server、PostgreSQL、MySQL / MariaDB | 服务器上存放这些表的数据库,最多 128 个字符。 | 空 |
| 数据库文件 | SQLite | “SQLite 文件的完整路径,使用运行工作站的账户的 Windows 权限访问。除非有点位写入,否则以只读方式打开。”框中以 C:\Data\recipes.db 作为提示。从不创建该文件。 |
空 |
| 数据源或连接字符串 | 其他(ODBC) | “Windows‘ODBC 数据源(64 位)’中的数据源名称,或类似 Driver=;Dbq=C:\Data\plant.accdb 的连接字符串。密码填在密码框里,绝不写进连接字符串。” | 空 |
所选类型不读取的字段不会显示,并保留其值以备将来读取。选择另一种类型时,仍停留在旧数据库自身端口的端口会被清空,这样新数据库就在它自己的端口上连接。“服务器”框会把数据库工具写在一起的内容拆开:
| 在“服务器”中输入 | 结果 |
|---|---|
mes-sql\SQLEXPRESS(SQL Server) |
服务器 mes-sql,实例名称 SQLEXPRESS |
mes-sql,1433(SQL Server) |
服务器 mes-sql,端口 1433 |
10.0.0.5:5433 |
服务器 10.0.0.5,端口 5433 |
在卡片说明数据库的位置之前,设备按原样保存并等待,灰色圆点,不读取任何内容,也不显示错误:
| 数据库类型 | 等待 | 设备显示 |
|---|---|---|
| SQL Server、PostgreSQL、MySQL / MariaDB | 服务器,然后是数据库名称 | “尚未填写服务器”,然后是“尚未填写数据库名称” |
| SQLite | 文件 | “尚未填写数据库文件” |
| 其他(ODBC) | 数据源或连接字符串 | “尚未填写数据源” |
卡片无法接受的设置会显示在卡片下方,修正之前设备不会保存:
| 您输入 | 卡片显示 |
|---|---|
含协议前缀、路径或空格的服务器,例如 http://mes-sql |
“服务器只填主机名或 IP 地址:不含协议前缀、路径或空格。与之一起写的 SQL Server 实例和端口会移到各自的框中。” |
含空格或 _、$ 以外符号的实例名称 |
“实例名称最多 16 个字符,可用字母、数字、下划线和美元符号。” |
| 超过 128 个字符的数据库名称 | “数据库名称最多 128 个字符,不含控制字符。” |
不是完整路径的文件,例如 recipes.db |
“数据库文件是完整路径:驱动器、文件夹和文件(C:\Data\recipes.db),或网络共享(\server\data\recipes.db)。” |
文件夹,或含 *、?、<、> 或引号的路径 |
“请填写数据库文件本身的路径,而不是文件夹,不含 * ? | < > 或引号。” |
含方括号、大括号、圆括号、逗号、分号或 ? * ! @ \ 之一的数据源名称 |
卡片要求填写该数据源在 ODBC 数据源中的名称,或连接字符串。 |
不是 key=value 对的连接字符串,例如留着未闭合的大括号 |
“连接字符串是以分号分隔的 key=value 对;含分号的值要放在大括号中。” |
含 PWD= 或 Password= 的连接字符串 |
“请把密码从连接字符串中拿出,填到密码框里:连接字符串会显示并写入诊断日志,而密码框会加以保护。” |
保存遵循同样的规则,拒绝时动态栏会说明:“设备‘MES’有驱动无法使用的数据库设置。请打开它并修正面板标出的字段。”
“登录”卡片
除 SQLite 之外的每种数据库都有登录卡片,其中是工作站登录所用的用户。
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 使用工作站的 Windows 账户登录 | SQL Server | 打开:“使用运行工作站的 Windows 账户登录 SQL Server;不保存用户或密码。”关闭:“使用数据库用户及其密码登录 SQL Server。” | 关闭 |
| 用户名 | 用用户登录的服务器,以及可选的 ODBC | 数据库用户。 | 空 |
| 密码 | 同上 | 用户的密码,和驱动的其他凭据一样受保护地保存:不再显示,不写入地址或诊断日志,也不返回给智能体。 | 空 |
| 加密 | SQL Server | 加密,校验证书:“连接经过加密,服务器证书会与此计算机信任的证书进行校验。”加密,接受任何证书:“连接经过加密,并接受任何证书,这是使用自有证书的工厂服务器所需要的。不校验服务器的身份。”不加密:“值和命令以明文传输。仅用于不提供加密的旧服务器。” | 加密,校验证书 |
PostgreSQL 和 MySQL 没有“加密”字段:只要服务器提供,它们的连接就会加密。使用自有证书的 SQL Server(工厂服务器常常如此)会以数据库自己的话拒绝连接,说证书链由不受信任的机构颁发:这种服务器需要选择加密,接受任何证书。
在字段下方,卡片说明应当申请什么样的用户:“请向数据库管理员申请一个只具备工作站所需权限的用户:读取权限,以及仅对其点位修改的表的写入权限。”工作站以该用户能做的一切去读写另一个系统的数据,因此这个用户才是工作站能修改内容的真正边界。每次写入都会记入诊断日志,和任何驱动一样。
用用户登录的服务器尚未填写用户时,会改为显示“请填写工作站登录所用的用户。在此之前,工作站不会连接这台设备。”这不是拒绝:设备会保存,在填写用户之前,它的错误会说明尚未填写数据库用户。
在线、等待和离线
| 情况 | 设备及其点位的行为 |
|---|---|
| “数据库”卡片没有说明数据库的位置 | 设备等待,灰色圆点,不读取任何内容,也没有错误(见上文)。 |
| 用用户登录的服务器,且未填写用户 | 工作站不连接该设备;其错误说明尚未填写数据库用户。 |
| 服务器没有响应、拒绝登录,或 SQLite 文件不存在 | 设备离线,并附上数据库自己给出的原因,工作站在可以时立即连接。连接最多等待 10 s。 |
| 连接断开(服务器重启、网络中断) | 设备离线,然后重新连接。 |
| 数据库拒绝的语句,或 10 s 后仍在运行的语句 | 该点位读取失败,并附上数据库自己的话;设备继续读取其他点位。 |
| 点位读取还没有任何行的表的最新一行 | 该点位等待,没有错误,在写入第一行之前,设备的健康状态不把它算在内:设备是否在线由其他点位说明。点位读取过之后被清空的表不属于这种等待:点位保留上一次读数,和任何驱动一样,当它比轮询间隔加 10 s 还旧时就算作失败。 |
每台设备都有自己的连接,在连接时打开,从不共享,也不放入连接池,因此服务器断开的连接不会再被使用。
准备服务器
在常见的安装中,这三种网络数据库出厂时对其他计算机是关闭的。下面每一项设置都由服务器的管理员在服务器上完成;工作站不会改动其中任何一项。
| 数据库 | 把工作站挡在外面的原因 | 修改位置 |
|---|---|---|
| SQL Server | TCP/IP 关闭(SQL Server Express 和 Developer 出厂即如此) | SQL Server Configuration Manager > SQL Server Network Configuration > Protocols for 实例:启用 TCP/IP,然后在 SQL Server Services 中重启 SQL Server(该实例) |
| SQL Server | 命名实例在自己选择的端口上侦听 | TCP/IP > IP Addresses > IPAll:清空 TCP Dynamic Ports,在 TCP Port 中填入端口,然后重启;或让设备的“端口”框留空并填写实例名称 |
| SQL Server | 没有端口的命名实例要靠 SQL Server Browser 定位,而它已停止或被阻挡(错误 26) | SQL Server Services:启动 SQL Server Browser,Start Mode 设为 Automatic;在服务器防火墙中允许 UDP 1434 |
| PostgreSQL | listen_addresses 是默认值 localhost | postgresql.conf:listen_addresses = '*',然后重启 PostgreSQL |
| PostgreSQL | pg_hba.conf 中没有一行放行本工作站的地址(SQLSTATE 28000) | pg_hba.conf:为该数据库、该用户和本工作站的地址加一行 host,方法为 scram-sha-256(以 MD5 保存的密码用 md5),然后执行 SELECT pg_reload_conf(); |
| MySQL、MariaDB | bind-address 是 127.0.0.1(许多软件包都这样设置),或 skip-networking 已开启 | 配置文件的 [mysqld] 段:bind-address = 0.0.0.0,删除 skip-networking,然后重启 |
| MySQL、MariaDB | 没有对应本工作站地址的账户(错误 1130) | 用 CREATE USER 为本工作站地址上的该用户建账户,并用 GRANT 授予点位所需的权限 |
无论哪种情况,都还需要在服务器所在计算机的防火墙中允许数据库端口。服务器以其中一种方式答复时,设备页面会代替数据库的英文错误,说明是哪项设置,并给出这些步骤和此设备的值(端口、实例、服务器看到的本工作站地址、pg_hba.conf 的那一行和 MySQL 账户,各带一个复制按钮)。设备一旦连接,或服务器以别的方式答复,此提示就会自行消失。日志和代理读到的是同样的步骤。
点位寻址
点位如何读取
此驱动的点位没有自己的地址框:它的信号源卡片询问它如何读取。
| 读取内容 | 点位显示的内容 | 其字段 |
|---|---|---|
| 表和列 | 一个单元格:表中某一行的值列。 | 表、值列、要读取的行以及行的字段 |
| 自定义查询 | 自己的 SELECT 返回的第一行第一列。 | 查询文本 |
新点位按键读取表和列,类型为 Double。提供的类型有 Boolean、Int32、Int64、Float、Double、String 和 DateTime。读取单元格时,整数点位会拒绝带小数部分的值而不是将其舍入(写入则相反,见写入),文本只有在它是数字时才按数字读取。每个点位新建时都是只读;写入增加的内容见写入。
表和列
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 表 | 表和列 | “一个名称,或架构加名称(dbo.Orders)。含空格或大写字母的名称要放在引号或方括号中,例如 [Order Lines]。” | 空 |
| 值列 | 表和列 | 其单元格就是点位值的那一列。 | 空 |
| 要读取的行 | 表和列 | 按键:“键列中为该键值的那一行。同一表、同一行的点位在一次查询中一起读取。”最新一行:“日期列值最大的那一行:日期时间,或只增不减的数字。同一表、同一行的点位在一次查询中一起读取。” | 按键 |
| 键列 | 按键 | 选定行的列,例如 OrderNo。 |
空 |
| 键值 | 按键 | 要读取的那一行中键列的值,例如 4711,以文本输入:数据库按该列的值来读取它。 |
空 |
| 日期列 | 最新一行 | 其最大值所在的行即最新一行的列,例如 updated_at。 |
空 |
名称按数据库读取的方式读取:
| 写法 | 读取方式 |
|---|---|
Orders |
普通名称,按数据库读取任何普通名称的方式读取:PostgreSQL 为小写,Oracle 为大写。 |
"Order Lines"、[Order Lines] |
名称本身,不论数据库自己接受哪种引号。 |
dbo.Orders |
架构和表:引号外的点把两者分开。 |
驱动会把名称的每一部分放进其数据库接受的引号中,因此名称从不会作为文本拼接进语句。字段无法工作的点位不会保存,其页面会说明缺少什么:
| 您留空或输入 | 点位页面显示 |
|---|---|
| 没有表 | “请填写值所在的表。” |
| 由三部分组成的表,或未闭合的引号 | “表是一个名称,或架构加名称(dbo.Orders);含空格的名称要放在引号或方括号中。每部分最多 128 个字符。” |
| 没有值列 | “请填写值所在的列。” |
| 由两部分组成的值列 | “值列是单个名称;含空格的名称要放在引号或方括号中。” |
| 按键,没有键列 | “请填写用来选定行的键列。” |
| 按键,没有键值 | “请填写键值:要读取的那一行中键列的值。” |
| 最新一行,没有日期列 | “请填写日期列,其最大值所在的行即最新的一行。” |
只读的源地址(总线)一行显示驱动收到的内容:按键选行为 row?table=dbo.ProductionOrders&column=Quantity&key=OrderNo&equals=4711,最新一行为 newest?table=recipe_setpoints&column=oven_temperature&by=updated_at。
自定义查询
| 字段 | 含义 | 默认值 |
|---|---|---|
| 查询文本 | “一个只读的 SELECT;值为第一行第一列。@now 是工作站的日期和时间。”以 WITH 开头且只读的查询也可以接受。 | 空 |
查询按数据库读取的方式读取:引号中的文本、引号中的名称或注释中的内容不算语句中的词。不只读取的查询会在输入处被拒绝:
| 您输入 | 点位页面显示 |
|---|---|
| 什么都没有 | “请填写查询:一个 SELECT,其第一行第一列就是值。” |
不是 SELECT 的语句,例如 UPDATE 或 DELETE |
“查询以 SELECT 或 WITH 开头。要写入,请让点位的访问方式允许写入,并使用写入命令。” |
修改数据库的 SELECT:SELECT ... INTO、FOR UPDATE,或含 INSERT、UPDATE、EXEC 的 SELECT |
“该查询会修改数据库(INSERT、UPDATE、SELECT INTO、FOR UPDATE、EXEC 等)。查询只能读取。” |
| 两条语句 | “查询包含多条语句。请只保留一个 SELECT。” |
| 未闭合的引号、括号或注释 | “查询中的引号、括号或注释没有闭合。” |
@now 以外的值,例如 @order |
“查询只接受 @now,即工作站的日期和时间。其他值请直接写进文本。” |
查询点位的总线地址是 query?sql= 后接经过百分号编码的查询。
读取
| 读取的点位 | 读取方式 |
|---|---|
| 按键 | 在键列等于键值的那一行中读取其列;键值作为参数传给数据库。 |
| 最新一行 | 在日期列取该列最大值的那一行中读取其列(WHERE ... = (SELECT MAX(...) FROM ...)),这种写法所有数据库和 ODBC 都以同样方式读取;两行并列时读取第一行。 |
| 同一表、同一行的多个点位 | 每轮用一次查询读取它们所有的列,以免为每个点位都询问工厂的数据库。如果数据库拒绝这次查询(表中没有的列),就单独读取该点位自己的列,此后该行逐列读取:错误的列只影响它自己的点位。 |
| 自定义查询 | 按原样执行查询,@now 作为参数传入。 |
| 数据库返回 | 点位 |
|---|---|
| 点位可读取类型的值 | 读取它。 |
| 空单元格(NULL) | 读取失败。 |
| 没有行含该键值,或不止一行 | 读取失败:一个点位只读取一行。 |
| 还没有任何行的表的最新一行 | 等待,没有错误。 |
| 不返回任何行的查询 | 读取失败。 |
| 点位类型无法读取的值(Int32 点位中的文本、整数点位中的小数部分) | 读取失败,并附上原因。 |
读取失败时点位保留上一次读数,和任何驱动一样,当它比轮询间隔加 10 s 还旧时就算作失败。每次读取都会询问数据库:其他程序做的修改在下一次读取时才能看到,而不是修改的那一刻。
写入
只有在点位的访问为读写或只写之后,点位才会写入。此时它的信号源卡片会增加写入的方式:
| 字段 | 显示条件 | 含义 | 默认值 |
|---|---|---|---|
| 写入方式 | 点位写入时 | 修改所读取的单元格:“修改此点位所读取的单元格,只改一行。仍在等待的较新值会取代较旧的值。”执行其写入命令:“执行下面的写入命令。每次写入都算数:仍在等待的写入不会因为较新的写入而被丢弃。”读取自定义查询的点位没有可修改的单元格,只提供执行其写入命令。 | 修改所读取的单元格 |
| 写入命令 | 执行其写入命令 | “带 WHERE 的 UPDATE、INSERT 或存储过程调用。@value 是写入的值,@now 是工作站的日期和时间;值总是作为参数传入,从不拼接进文本。”空框中以 INSERT INTO results (result, recorded_at) VALUES (@value, @now) 作为提示。 |
空 |
执行写入命令的只写点位不读取任何内容,因此它的信号源卡片只有写入。
| 写入 | 执行方式 |
|---|---|
| 修改所读取的单元格 | 一条 UPDATE,在点位那一行把值列设为 @value,放在事务中执行,除非恰好改动一行,否则撤销:没有行含有的键值,或两行都含有的键值,都不写入任何内容并说明原因。和任何设定值一样,仍在等待的较新值会取代较旧的值。 |
| 执行其写入命令 | 每次写入执行一次命令,值作为 @value,工作站的日期和时间作为 @now。每次写入都算数:两次 INSERT 就是两行,仍在等待的写入不会因为较新的写入而被丢弃。存储过程用 EXEC、CALL 或 ODBC 的 {call ...} 调用。 |
| 整数点位上带小数部分的值 | 被舍入,而不是被拒绝:向没有量程换算和校准的整数点位(Int32 或 Int64)写入带小数部分的值,会在到达数据库之前四舍五入到最近的整数,一半时远离零(2.5 写入 3,-2.5 写入 -3)。拒绝小数部分是读取单元格的方式,不是写入值的方式。 |
| 答复 | 完成,或以数据库自己的话拒绝:用户缺少的权限、该行违反的约束、该列不接受的值。 |
驱动无法执行的命令会在点位页面被拒绝:
| 您输入 | 点位页面显示 |
|---|---|
| 什么都没有 | “请填写写入命令:包含 @value 的 UPDATE、INSERT 或存储过程调用。” |
以其他词开头的命令,例如 DELETE |
“写入命令以 UPDATE、INSERT、EXEC 或 CALL 开头。” |
| 两条语句 | “写入命令包含多条语句。请只保留一条,或调用存储过程。” |
| 未闭合的引号、括号或注释 | “写入命令中的引号、括号或注释没有闭合。” |
没有 @value |
“请把 @value 放在写入值的位置:值总是作为参数传入,从不拼接进文本。” |
@value 和 @now 以外的值,例如 @line |
“写入命令只接受 @value(写入的值)和 @now(工作站的日期和时间)。” |
| 不带 WHERE 的 UPDATE | “不带 WHERE 的 UPDATE 会修改表中的每一行。请加上选定该行的 WHERE。” |
以 @@ 开头的名称(SQL Server 的函数)和 EXEC 的参数名(@speed = @value)不是值,按原样保留。保存遵循同样的规则,拒绝点位时动态栏会说明:“点位‘Order quantity’没有说明其值在数据库中的位置,或含有驱动拒绝的查询或写入命令。请打开它并修正点位面板标出的字段。”
总线地址会加上写入:单元格为 row?table=recipes&column=setpoint&key=code&equals=R-100&write=cell,执行命令的只写点位为 none?write=command&command= 后接命令。
设备发现
“扫描范围”卡片
有配置 Connector 的权限时,驱动页面上有扫描范围卡片,其下一行写着“以设备的方式登录,为其各表的每一列提供一个点位,取最新一行或键最小的那一行。”
| 字段 | 含义 | 默认值 |
|---|---|---|
| 要扫描的设备 | 按名称选择此驱动的一台设备。数据库只能通过保存其登录信息的设备来扫描;设备中仍在等待保存的修改会先保存。 | 按名称排序的第一台设备 |
| 表 | “留空表示所有表,也可以写名称或用 * 代表任意字符的模式,例如 Recipe*。” | 空 |
没有设备的驱动只显示“数据库通过保存其登录信息的设备来扫描。请添加此驱动的设备,并说明其数据库的位置。”范围中仍缺少的内容会以红色显示在卡片下方,在范围完整之前发现设备一直是灰色的:
| 范围 | 卡片显示 |
|---|---|
| 没有说明数据库位置的设备,或有驱动无法使用的设置的设备 | “设备‘Recipes’尚未说明其数据库的位置,或有驱动无法使用的设置。请先完成它的‘数据库’卡片。” |
含架构、引号、方括号或分号的模式,例如 dbo.Recipe* |
“‘dbo.Recipe*’不是表名或模式。请写一个名称,或用 * 代表任意字符的模式,不带架构或引号。” |
| 已不存在的设备 | “所选的扫描设备已不存在。请另选一台要扫描的设备。” |
要扫描的设备有无法保存的修改时,扫描不会开始:“设备发现没有开始,因为要扫描的设备的修改无法保存。”
扫描提供的内容
扫描以设备的方式登录,读取数据库自己保存的表和视图(不含系统表)及其列的清单,并说明正在读取哪个表,例如“正在读取 recipes 的列…”。它提供一个候选项,即设备本身,标记为已经配置过:其卡片列出设备尚无点位读取的列,并已勾选,添加所选点位位于打开之前,把勾选的列以只读方式添加到设备。
| 表 | 其候选点位 |
|---|---|
| 有日期时间列 | 每列一个,按第一个这样的列读取最新一行。 |
| 没有 | 除键之外每列一个,读取主键(没有主键的表则为第一列)值最小的那一行:要读取另一行,请修改点位的键值。 |
| 没有,也没有任何行 | 不提供。 |
| 任何点位类型都无法读取的列(二进制数据、几何数据) | 不提供,并在结束扫描的那一行中计数。 |
点位以其表和列命名(recipes.oven_temperature),类型取自列的类型,每一个都是只读。一次扫描最多读取 100 个表和 500 个值;在此截断的扫描会显示“Recipes 的扫描提前停止。一次扫描最多读取 100 个表和 500 个值:请指定表名或模式以查看其余部分。”扫描的其他行为见设备发现。
设备自己的页面不经过驱动页面也能做同样的事:点位卡片标题栏里的发现点位像设备那样登录,按设备保存的样子扫描它的数据库,只列出它还没有点位的列(见发现一台设备的点位)。
示例:来自 SQL Server 的生产订单
MES 把生产订单保存在 SQL Server 中 MES 数据库的 dbo.ProductionOrders 表里,每个订单号一行:
- 在驱动页面点添加设备,命名为
MES。在数据库卡片上保留 SQL Server,服务器填写mes-sql(命名实例则为mes-sql\SQLEXPRESS),端口留空,数据库名称填写MES。 - 在登录卡片上,用户名填写
station_reader及其密码,或打开使用工作站的 Windows 账户登录。对于使用自有证书的工厂服务器,选择加密,接受任何证书。 - 添加点位
Order quantity,Int32:表dbo.ProductionOrders,值列Quantity,要读取的行 按键,键列OrderNo,键值4711。其总线地址为row?table=dbo.ProductionOrders&column=Quantity&key=OrderNo&equals=4711。 - 添加点位
Product,String,同一表同一行,值列ProductCode:两个点位在一次查询中读取。
使用工具时:
device_upsert name=MES driver=Database databaseKind=SqlServer host="mes-sql\SQLEXPRESS" databaseName=MES username=station_reader password=<password> databaseEncryption=TrustServerCertificate
tag_upsert device=MES name="Order quantity" opcUaType=Int32 databaseTable=dbo.ProductionOrders address=Quantity databaseRow=Key databaseKeyColumn=OrderNo databaseKeyValue=4711
tag_upsert device=MES name=Product opcUaType=String databaseTable=dbo.ProductionOrders address=ProductCode databaseRow=Key databaseKeyColumn=OrderNo databaseKeyValue=4711
示例:来自 PostgreSQL 的配方设定值
配方系统每次设定值改变时都会在 recipe_setpoints 中添加一行,并在 updated_at 列中记录日期:
- 点添加设备,命名为
Recipes,数据库类型 PostgreSQL,服务器recipes-db,端口留空(PostgreSQL 的 5432),数据库名称recipes,然后在登录卡片上填写用户名和密码。 - 添加点位
Oven setpoint,Double:表recipe_setpoints,值列oven_temperature,要读取的行 最新一行,日期列updated_at。
每个新行会在点位的下一次读取时读到。PostgreSQL 按小写读取普通名称,因此用大写字母创建的列(例如 OvenTemp)要放在引号中写成 "OvenTemp"。使用工具时:
device_upsert name=Recipes driver=Database databaseKind=PostgreSql host=recipes-db databaseName=recipes username=station password=<password>
tag_upsert device=Recipes name="Oven setpoint" opcUaType=Double databaseTable=recipe_setpoints address=oven_temperature databaseRow=Newest databaseDateColumn=updated_at
示例:用 INSERT 写入的结果行
质量系统希望每个测量过的零件在其 test_results 表中有一行:
- 在该数据库的设备上,添加点位
Result,Double,访问设为只写。 - 写入方式选执行其写入命令,并在写入命令中写入添加该行的
INSERT INTO test_results (result, recorded_at) VALUES (@value, @now)。
Logic 写入 Result 的每个值都成为单独的一行,旁边是工作站的日期和时间;快速连续的写入都会按顺序保留,不会因为较新的写入而丢弃。读取单元格的读写点位则会在每次写入时修改它的那一行。使用工具时:
tag_upsert device=Quality name=Result opcUaType=Double accessType=WriteOnly databaseWriteMode=Command databaseCommand="INSERT INTO test_results (result, recorded_at) VALUES (@value, @now)"
示例:通过 ODBC 访问 Access 和 Oracle
| 数据库 | 此计算机上需要 | 设备上的设置 |
|---|---|---|
| Microsoft Access | Microsoft 的 Access Database Engine,64 位 | 数据库类型 其他(ODBC),数据源或连接字符串 Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=C:\Data\plant.accdb,无用户 |
| Oracle | Oracle 的 64 位 ODBC 驱动,以及用它在 ODBC 数据源(64 位)中创建的数据源 ERP |
数据库类型 其他(ODBC),数据源或连接字符串 ERP,在登录卡片上填写用户名和密码 |
当设备指定的数据源或驱动只对 32 位程序存在(32 位 Office 的 Access、在“ODBC 数据源(32 位)”中创建的数据源),或这台计算机上根本没有时,只要设备处于启用状态且未能连接,设备面板就会连同设备给出的名称说明是哪一种情况,并给出完整的说明。设备的错误用英文说明同样的内容,driver_capabilities 也在 Database 驱动的 prerequisite(perDevice 为 true)中说明同样的内容:
| 部分 | 内容 |
|---|---|
| 缺少什么 | 该数据源或驱动的 64 位 ODBC 驱动:Ganter Lab 是 64 位程序,只能看到 64 位 ODBC 驱动以及用它们创建的数据源,并且不能包含其他厂商的驱动 |
| 从哪里获取 | 数据库厂商;对于 Access,是 Microsoft 的页面“Download and install Microsoft 365 Access Runtime”,其运行时带有 Access Database Engine |
| 选择哪个 | 64 位版本(对于 Access,即您所用语言的 64 位下载按钮),不要选 32 位版本 |
| 如何安装 | 以管理员身份运行;然后,如果设备指定的是数据源名称,请在“ODBC 数据源(64 位)”中用相同的名称和相同的数据库创建它 |
| 常见问题 | 在装有 Office 的计算机上安装 Access 时:Microsoft 的页面说,安装的 Access Runtime 与已安装的 Office 相匹配,并且与通过 Windows Installer 安装的 Office 不兼容;Microsoft 关于在 Office 64 位和 32 位版本之间选择的页面说,要先卸载一个版本,再安装另一个版本 |
| 之后 | 在下一次连接尝试时,设备以现有配置连接,无需重启 Ganter Lab |
提示的最后列出这台计算机上的 64 位 ODBC 驱动,名称即 Driver={...} 中所写的名称。64 位一侧已有、却仍然失败的数据源或驱动,显示驱动程序管理器自己的错误。
通过 ODBC 时,普通名称按数据库读取的方式读取(Oracle 上为大写),引号中的名称按原样读取;日期和时间精确到整秒发送,这是每个 ODBC 驱动都接受的最细精度。使用工具时:
device_upsert name="Plant book" driver=Database databaseKind=Odbc databaseOdbc="Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=C:\Data\plant.accdb"
device_upsert name=ERP driver=Database databaseKind=Odbc databaseOdbc=ERP username=STATION password=<password>
智能体工具
driver_capabilities 在 database 下描述此驱动:简单路径,每种数据库及其字段和自己的端口,加密选项,点位的两种读取方式和两种写入方式,值只能以 @value 或 @now 进入语句的规则,类型,超时,关于数据库用户的建议,设备发现,以及四个完整示例。device_upsert driver=Database 接受 databaseKind(默认的 SqlServer、PostgreSql、MySql、Sqlite 或 Odbc),服务器接受 host(SQL Server 的 server\INSTANCE 或 server,port 会被拆开)、port、databaseName,SQL Server 还接受 databaseInstance、databaseWindowsSignIn 和 databaseEncryption(Verified、TrustServerCertificate 或 Off);SQLite 接受 databaseFile,ODBC 接受 databaseOdbc;以及 username 和从不返回的 password。它返回的设备带有 database,其中有地址以及设备是否仍在等待其用户。tag_upsert 以 address 接受值列,并接受 databaseSource(Fields 或 Query)、databaseTable、databaseRow(Key 或 Newest)、databaseKeyColumn、databaseKeyValue、databaseDateColumn、databaseQuery,在 accessType 写入时还接受 databaseWriteMode(Cell 或 Command)和 databaseCommand;除非 opcUaType 另有指定,新点位为只读的 Double。device_discover driver=Database 接受此驱动已配置设备的名称 databaseDevice,以及可选的 databaseTables(表名或带 * 的模式);设备缺少的点位用 tag_upsert 添加。connector_browse 返回每台设备的 databaseKind。其他工具见智能体工具。
值得了解的限制
- 驱动读写其点位的值,每个点位一个值。它不会把工作站的运行记录写入数据库:每次运行一行、包含序列号、判定和测量值,这不是此驱动写入的内容。
- 产品不附带任何 ODBC 驱动。Oracle、Access、Firebird 以及直接连接的四种以外的任何数据库,都需要在计算机上安装其自己的 64 位 ODBC 驱动;32 位的驱动无法识别。
- 设备不保存任何 Windows 密码:登录 SQL Server 的 Windows 登录,以及网络共享上的 SQLite 文件,都使用运行工作站的账户,因此数据库或共享必须允许该账户访问。
- 查询只能读取。修改数据库的是写入,而写入只发生在访问方式允许写入的点位上。
- 值从不进入语句的文本:写入的值总是参数
@value,工作站的日期和时间是@now,键值也是参数。命名任何其他值的语句都会被拒绝。 - 单元格写入恰好修改一行;UPDATE 命令需要它的 WHERE。
- 每次读取都会询问数据库:其他程序做的修改在下一次读取时看到,同一行有许多点位的数据库每轮只为它们全部询问一次。
- 不读取二进制列。