InterSystems IRIS 进程表

点 赞
1
热 度
35
评 论
0
  1. 首页
  2. Intersystem IRIS
  3. 基础Cache
  4. InterSystems IRIS 进程表

背景与痛点

InterSystems IRIS 是一个强大的数据平台,其底层支持名为 Global 的数据结构。然而,并非所有数据都会映射到标准的 SQL 表中:

  • 数据可能直接存储在 Global 中。

  • 数据可能定义在类的参数里。

对于这些数据,常规的 SELECT ... FROM table 方式无法直接查询。通常,我们只能通过调用存储过程(CALL) 来获取它们。但这带来了几个问题:

  1. 迁移兼容性:代码迁移到低版本 Caché 数据库时,数据类型定义可能出错,且可能不再支持 SELECT 调用存储过程的方式。

  2. 对第三方开发者不友好:对于熟悉 SQL 但不熟悉 ObjectScript 的开发者来说,使用 CALL 语法不够直观。

本文将介绍一种称为 “进程表” 的方案,它巧妙结合了 Global 和 SQL 表的特性,让您能够用标准的 SELECT 语句查询这类“非表”数据。

什么是“进程表”?

进程表是一种虚拟的 SQL 表。它的核心思路是:

  1. 创建一个标准的持久化类(对应 SQL 表结构)。

  2. 手动修改其存储定义,将数据存储位置指向进程私有 Global(格式为 ^||GlobalName)。这种 Global 仅存在于当前进程中,生命周期随进程结束而结束,非常适合用作临时数据容器。

  3. 编写一个类方法(标记为 SQL 存储过程),在该方法中将您想查询的数据(无论是来自 Global、类参数还是其他逻辑)写入这个进程私有 Global。

  4. 通过一个特殊的 WHERE 子句调用该方法,从而“填充”这个虚拟表,并用 SELECT 查询出结果。

调用形式最终将统一为:

sql

SELECT * FROM YourTable WHERE YourTable_Method() = 1

完整示例

以下是一个名为 User.People 的“进程表”实现示例,它生成100条模拟的人员数据。

objectscript实体类

Class User.People Extends %Persistent{
   /// 姓名
   Property Name As %String;
   /// 出生日期
   Property DateOfBirth As %Date;
   /// 性别
   Property Gender As %String;
}

Query代码

/// 核心方法:填充进程表数据
/// 将此方法定义为SQL存储过程,它将在SELECT的WHERE子句中被调用
ClassMethod GLB(Args...) As %Status [ Language = objectscript, SqlProc ]
{
    // 设置错误处理
    s $zt="Error"
// 清空进程Global,确保每次查询都是新数据
k ^||User.PeopleD, ^||User.PeopleI

// 循环生成100条示例数据
for i=1:1:100 {
    // 随机生成性别代码 (1 或 2)
    s genderCode = $r(2) + 1

    // 使用工具类生成随机的姓名和日期
    s name = ##class(%PopulateUtils).Name(genderCode)
    s dob = ##class(%PopulateUtils).Date(+$h-2000, +$h-10)

    // 将性别代码转换为文本
    s genderText = $case(genderCode, 1:"Male", 2:"Female", :"Unknown")

    // 将数据以 $listbuild 格式存入进程Global
    // 注意:第一个元素通常留空或用于其他用途
    s ^||User.PeopleD($i(^||User.PeopleD)) = $lb("", name, dob, genderText)
}

// 返回成功状态
q $$$OK

Error
// 错误处理块
s $zt=""
// 将错误信息写入Global,以便在查询结果中看到
s ^||User.PeopleD($i(^||User.PeopleD)) = $lb("", "ERROR: "_$ze)
q $$$OK
}

/// 存储定义 - 这是关键,将数据位置指向进程私有Global
Storage Default
{
<Data name="PeopleDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Name</Value>
</Value>
<Value name="3">
<Value>DateOfBirth</Value>
</Value>
<Value name="4">
<Value>Gender</Value>
</Value>
</Data>
<!-- 注意前缀 ^|| ,这表示进程私有Global –>
<DataLocation>^||User.PeopleD</DataLocation>
<DefaultData>PeopleDefaultData</DefaultData>
<IdLocation>^||User.PeopleD</IdLocation>
<IndexLocation>^||User.PeopleI</IndexLocation>
<StreamLocation>^||User.PeopleS</StreamLocation>
<Type>%Storage.Persistent</Type>
}

如何使用?

  1. 编译上述 User.People 类。

  2. 在 SQL Shell 或任何 SQL 查询工具中,执行以下查询:

sql

SELECT * FROM User.People WHERE People_GLB() = 1

执行过程解析:

  1. WHERE People_GLB() = 1 会触发 GLB 类方法的执行。

  2. GLB 方法会向 ^||User.PeopleD 中写入100条数据。

  3. SQL 引擎会从 ^||User.PeopleD 中读取数据,并按照 User.People 表的定义进行格式化。

  4. 最终返回一个包含100行记录的标准结果集。

关键要点与注意事项

  1. 固定调用模式SELECT ... WHERE TableName_Method() = 1 是一个固定模式= 右边的值会作为参数传递给方法,但方法本身必须返回状态,=1 是约定俗成的写法,表示“执行该方法以准备数据”。

  2. 异常捕获至关重要GLB 方法中的 $zt 错误处理是必须的。它可以防止存储过程执行出错导致整个 SQL 查询崩溃,而是将错误信息作为一行数据返回,保证查询能完成。

  3. 内存考虑:此方案会在 IRIS 进程内存中构建结果集。如果用于导出海量数据(例如百万、千万行),请确保为 IRIS 分配了足够的内存,否则可能导致 错误。

  4. 方案适用性:进程表是一种将任意数据“伪装”成 SQL 表的通用适配器方案。它特别适用于:

    • 将复杂的 Global 结构暴露给 BI 报表工具。

    • 让只会 SQL 的第三方人员能查询系统内部数据。

    • 临时性的、一次性的数据抽取和转换。

    • 是否采用,需根据具体的性能要求、数据量和使用场景来权衡。


余乃云水散人,栖于数字之墟。性耽幽静,常以青简为田,墨痕为穗。晨起推窗,听松风煮茶;夜阑掩卷,伴竹影扫阶。此间筑小筑三椽,藏闲话若干:或遇史海遗珠,则录以素札;偶得诗瓢碎玉,便缀作清吟。往来皆烟霞客,谈笑有鸿儒踪。诸君若得暇,不妨暂驻云履,共品一盏烟岚,半卷春秋。

具有版权性

请您在转载、复制时注明本文 作者、链接及内容来源信息。 若涉及转载第三方内容,还需一同注明。

具有时效性

文章目录

欢迎来到南鸢宸羲的站点,为您导航全站动态

179 文章数
39 分类数
1 评论数
48标签数
最近评论
西北技术支持中心

西北技术支持中心


开始建站了😀